diff options
Diffstat (limited to 'lib/libdisk')
-rw-r--r-- | lib/libdisk/Makefile | 51 | ||||
-rw-r--r-- | lib/libdisk/blocks.c | 41 | ||||
-rw-r--r-- | lib/libdisk/change.c | 82 | ||||
-rw-r--r-- | lib/libdisk/chunk.c | 433 | ||||
-rw-r--r-- | lib/libdisk/create_chunk.c | 396 | ||||
-rw-r--r-- | lib/libdisk/disk.c | 494 | ||||
-rw-r--r-- | lib/libdisk/disklabel.c | 33 | ||||
-rw-r--r-- | lib/libdisk/libdisk.3 | 331 | ||||
-rw-r--r-- | lib/libdisk/libdisk.h | 325 | ||||
-rw-r--r-- | lib/libdisk/rules.c | 285 | ||||
-rw-r--r-- | lib/libdisk/tst01.c | 298 | ||||
-rw-r--r-- | lib/libdisk/write_disk.c | 284 |
12 files changed, 3053 insertions, 0 deletions
diff --git a/lib/libdisk/Makefile b/lib/libdisk/Makefile new file mode 100644 index 0000000..355018a --- /dev/null +++ b/lib/libdisk/Makefile @@ -0,0 +1,51 @@ +# $FreeBSD$ + +LIB= disk +SRCS= blocks.c disklabel.c dkcksum.c chunk.c disk.c change.c \ + create_chunk.c rules.c write_disk.c + +CFLAGS+= -Wall +CLEANFILES+= tmp.c tst01 tst01.o +VPATH= ${.CURDIR}/../../sbin/disklabel +NOPROFILE= yes +NOSHARED= yes +NOPIC= yes + +MAN3= libdisk.3 +MLINKS+= libdisk.3 Open_Disk.3 \ + libdisk.3 Clone_Disk.3 \ + libdisk.3 Free_Disk.3 \ + libdisk.3 Debug_Disk.3 \ + libdisk.3 Set_Bios_Geom.3 \ + libdisk.3 Delete_Chunk.3 \ + libdisk.3 Collapse_Disk.3 \ + libdisk.3 Collapse_Chunk.3 \ + libdisk.3 Create_Chunk.3 \ + libdisk.3 All_FreeBSD.3 \ + libdisk.3 CheckRules.3 \ + libdisk.3 Disk_Names.3 \ + libdisk.3 Set_Boot_Mgr.3 \ + libdisk.3 Set_Boot_Blocks.3 \ + libdisk.3 Write_Disk.3 \ + libdisk.3 Cyl_Aligned.3 \ + libdisk.3 Next_Cyl_Aligned.3 \ + libdisk.3 Prev_Cyl_Aligned.3 \ + libdisk.3 Track_Aligned.3 \ + libdisk.3 Next_Track_Aligned.3 \ + libdisk.3 Prev_Track_Aligned.3 \ + libdisk.3 Create_Chunk_DWIM.3 \ + libdisk.3 MakeDev.3 \ + libdisk.3 MakeDevDisk.3 \ + libdisk.3 ShowChunkFlags.3 \ + libdisk.3 ChunkCanBeRoot.3 \ + libdisk.3 slice_type_name.3 + +.include <bsd.lib.mk> + +beforeinstall: + ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/libdisk.h \ + ${DESTDIR}/usr/include/libdisk.h + + +tst01: tst01.o libdisk.a + cc ${CFLAGS} -static tst01.o -o tst01 libdisk.a diff --git a/lib/libdisk/blocks.c b/lib/libdisk/blocks.c new file mode 100644 index 0000000..10f5b31 --- /dev/null +++ b/lib/libdisk/blocks.c @@ -0,0 +1,41 @@ +/* + * ---------------------------------------------------------------------------- + * "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 <err.h> +#include "libdisk.h" + +void * +read_block(int fd, daddr_t block) +{ + void *foo; + + foo = malloc(512); + if (!foo) + err(1,"malloc"); + if (-1 == lseek(fd, (off_t)block * 512, SEEK_SET)) + err(1, "lseek"); + if (512 != read(fd,foo, 512)) + err(1,"read"); + return foo; +} + +void +write_block(int fd, daddr_t block, void *foo) +{ + if (-1 == lseek(fd, (off_t)block * 512, SEEK_SET)) + err(1, "lseek"); + if (512 != write(fd,foo, 512)) + err(1,"write"); +} diff --git a/lib/libdisk/change.c b/lib/libdisk/change.c new file mode 100644 index 0000000..6a506f8 --- /dev/null +++ b/lib/libdisk/change.c @@ -0,0 +1,82 @@ +/* + * ---------------------------------------------------------------------------- + * "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 "libdisk.h" + +void +Set_Bios_Geom(struct disk *disk, u_long cyl, u_long hd, u_long sect) +{ + disk->bios_cyl = cyl; + disk->bios_hd = hd; + disk->bios_sect = sect; + Bios_Limit_Chunk(disk->chunks,1024*hd*sect); +} + +void +Sanitize_Bios_Geom(struct disk *disk) +{ + int sane = 1; + + if (disk->bios_cyl > 1024) + sane = 0; + if (disk->bios_hd > 16) + sane = 0; + if (disk->bios_sect > 63) + sane = 0; + if (disk->bios_cyl*disk->bios_hd*disk->bios_sect != + disk->chunks->size) + sane = 0; + if (sane) + return; + + /* First try something that IDE can handle */ + disk->bios_sect = 63; + disk->bios_hd = 16; + disk->bios_cyl = disk->chunks->size/(disk->bios_sect*disk->bios_hd); + + if (disk->bios_cyl < 1024) + return; + + /* Hmm, try harder... */ + disk->bios_hd = 255; + disk->bios_cyl = disk->chunks->size/(disk->bios_sect*disk->bios_hd); + + return; +} + +void +All_FreeBSD(struct disk *d, int force_all) +{ + struct chunk *c; + + again: + for (c=d->chunks->part;c;c=c->next) + if (c->type != unused) { + Delete_Chunk(d,c); + goto again; + } + c=d->chunks; + if (force_all) { + Sanitize_Bios_Geom(d); + Create_Chunk(d,c->offset,c->size,freebsd,0xa5, + CHUNK_FORCE_ALL); + } else { + Create_Chunk(d,c->offset,c->size,freebsd,0xa5, 0); + } +} diff --git a/lib/libdisk/chunk.c b/lib/libdisk/chunk.c new file mode 100644 index 0000000..6116f54 --- /dev/null +++ b/lib/libdisk/chunk.c @@ -0,0 +1,433 @@ +/* + * ---------------------------------------------------------------------------- + * "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 <string.h> +#include <sys/types.h> +#include <err.h> +#include "libdisk.h" + +#define new_chunk() memset(malloc(sizeof(struct chunk)), 0, sizeof(struct chunk)) + +/* Is c2 completely inside c1 ? */ + +static int +Chunk_Inside(struct chunk *c1, struct chunk *c2) +{ + /* if c1 ends before c2 do */ + if (c1->end < c2->end) + return 0; + /* if c1 starts after c2 do */ + if (c1->offset > c2->offset) + return 0; + return 1; +} + +struct chunk * +Find_Mother_Chunk(struct chunk *chunks, u_long offset, u_long end, chunk_e type) +{ + struct chunk *c1,*c2,ct; + ct.offset = offset; + ct.end = end; + switch (type) { + case whole: + if (Chunk_Inside(chunks,&ct)) + return chunks; + case extended: + for(c1=chunks->part;c1;c1=c1->next) { + if (c1->type != type) + continue; + if (Chunk_Inside(c1,&ct)) + return c1; + } + return 0; + case freebsd: + for(c1=chunks->part;c1;c1=c1->next) { + if (c1->type == type) + if (Chunk_Inside(c1,&ct)) + return c1; + if (c1->type != extended) + continue; + for(c2=c1->part;c2;c2=c2->next) + if (c2->type == type + && Chunk_Inside(c2,&ct)) + return c2; + } + return 0; + default: + warn("Unsupported mother type in Find_Mother_Chunk"); + return 0; + } +} + +void +Free_Chunk(struct chunk *c1) +{ + if(!c1) return; + if(c1->private_data && c1->private_free) + (*c1->private_free)(c1->private_data); + if(c1->part) + Free_Chunk(c1->part); + if(c1->next) + Free_Chunk(c1->next); + free(c1->name); + free(c1); +} + +struct chunk * +Clone_Chunk(struct chunk *c1) +{ + struct chunk *c2; + if(!c1) + return 0; + c2 = new_chunk(); + if (!c2) err(1,"malloc failed"); + *c2 = *c1; + if (c1->private_data && c1->private_clone) + c2->private_data = c2->private_clone(c2->private_data); + c2->name = strdup(c2->name); + c2->next = Clone_Chunk(c2->next); + c2->part = Clone_Chunk(c2->part); + return c2; +} + +int +Insert_Chunk(struct chunk *c2, u_long offset, u_long size, const char *name, + chunk_e type, int subtype, u_long flags) +{ + struct chunk *ct,*cs; + + /* We will only insert into empty spaces */ + if (c2->type != unused) + return __LINE__; + + ct = new_chunk(); + if (!ct) err(1,"malloc failed"); + memset(ct,0,sizeof *ct); + ct->disk = c2->disk; + ct->offset = offset; + ct->size = size; + ct->end = offset + size - 1; + ct->type = type; + ct->name = strdup(name); + ct->subtype = subtype; + ct->flags = flags; + + if (!Chunk_Inside(c2,ct)) { + Free_Chunk(ct); + return __LINE__; + } + + if(type==freebsd || type==extended) { + cs = new_chunk(); + if (!cs) err(1,"malloc failed"); + memset(cs,0,sizeof *cs); + cs->disk = c2->disk; + cs->offset = offset; + cs->size = size; + cs->end = offset + size - 1; + cs->type = unused; + cs->name = strdup("-"); + ct->part = cs; + } + + /* Make a new chunk for any trailing unused space */ + if (c2->end > ct->end) { + cs = new_chunk(); + if (!cs) err(1,"malloc failed"); + *cs = *c2; + cs->disk = c2->disk; + cs->offset = ct->end + 1; + cs->size = c2->end - ct->end; + if(c2->name) + cs->name = strdup(c2->name); + c2->next = cs; + c2->size -= c2->end - ct->end; + c2->end = ct->end; + } + /* If no leading unused space just occupy the old chunk */ + if (c2->offset == ct->offset) { + c2->name = ct->name; + c2->type = ct->type; + c2->part = ct->part; + c2->subtype = ct->subtype; + c2->flags = ct->flags; + ct->name = 0; + ct->part = 0; + Free_Chunk(ct); + return 0; + } + /* else insert new chunk and adjust old one */ + c2->end = ct->offset - 1; + c2->size -= ct->size; + ct->next = c2->next; + c2->next = ct; + return 0; +} + +int +Add_Chunk(struct disk *d, long offset, u_long size, const char *name, + chunk_e type, int subtype, u_long flags) +{ + struct chunk *c1,*c2,ct; + u_long end = offset + size - 1; + ct.offset = offset; + ct.end = end; + ct.size = size; + + if (type == whole) { + d->chunks = c1 = new_chunk(); + if (!c1) err(1,"malloc failed"); + memset(c1,0,sizeof *c1); + c2 = c1->part = new_chunk(); + if (!c2) err(1,"malloc failed"); + memset(c2,0,sizeof *c2); + c2->disk = c1->disk = d; + c2->offset = c1->offset = offset; + c2->size = c1->size = size; + c2->end = c1->end = end; + c1->name = strdup(name); + c2->name = strdup("-"); + c1->type = type; + c2->type = unused; + c1->flags = flags; + c1->subtype = subtype; + return 0; + } + if (type == freebsd) + subtype = 0xa5; + c1 = 0; + if(!c1 && (type == freebsd || type == fat || type == unknown)) + c1 = Find_Mother_Chunk(d->chunks,offset,end,extended); + if(!c1 && (type == freebsd || type == fat || type == unknown)) + c1 = Find_Mother_Chunk(d->chunks,offset,end,whole); + if(!c1 && type == extended) + c1 = Find_Mother_Chunk(d->chunks,offset,end,whole); + if(!c1 && type == part) + c1 = Find_Mother_Chunk(d->chunks,offset,end,freebsd); + if(!c1) + return __LINE__; + for(c2=c1->part;c2;c2=c2->next) { + if (c2->type != unused) + continue; + if(Chunk_Inside(c2,&ct)) { + if (type != freebsd) + goto doit; + if (!(flags & CHUNK_ALIGN)) + goto doit; + if (offset == d->chunks->offset + && end == d->chunks->end) + goto doit; + + /* Round down to prev cylinder */ + offset = Prev_Cyl_Aligned(d,offset); + /* Stay inside the parent */ + if (offset < c2->offset) + offset = c2->offset; + /* Round up to next cylinder */ + offset = Next_Cyl_Aligned(d,offset); + /* Keep one track clear in front of parent */ + if (offset == c1->offset) + offset = Next_Track_Aligned(d,offset+1); + + /* Work on the (end+1) */ + size += offset; + /* Round up to cylinder */ + size = Next_Cyl_Aligned(d,size); + /* Stay inside parent */ + if ((size-1) > c2->end) + size = c2->end+1; + /* Round down to cylinder */ + size = Prev_Cyl_Aligned(d,size); + + /* Convert back to size */ + size -= offset; + + doit: + return Insert_Chunk(c2,offset,size,name, + type,subtype,flags); + } + } + return __LINE__; +} + +char * +ShowChunkFlags(struct chunk *c) +{ + static char ret[10]; + + int i=0; + if (c->flags & CHUNK_BSD_COMPAT) ret[i++] = 'C'; + if (c->flags & CHUNK_ACTIVE) ret[i++] = 'A'; + if (c->flags & CHUNK_ALIGN) ret[i++] = '='; + if (c->flags & CHUNK_PAST_1024) ret[i++] = '>'; + if (c->flags & CHUNK_IS_ROOT) ret[i++] = 'R'; + ret[i++] = '\0'; + return ret; +} + +void +Print_Chunk(struct chunk *c1,int offset) +{ + int i; + if(!c1) return; + for(i=0;i<offset-2;i++) putchar(' '); + for(;i<offset;i++) putchar('-'); + putchar('>'); + for(;i<10;i++) putchar(' '); + printf("%p %8ld %8lu %8lu %-8s %-8s 0x%02x %s", + c1, c1->offset, c1->size, c1->end, c1->name, + chunk_n[c1->type],c1->subtype, + ShowChunkFlags(c1)); + putchar('\n'); + Print_Chunk(c1->part,offset + 2); + Print_Chunk(c1->next,offset); +} + +void +Debug_Chunk(struct chunk *c1) +{ + Print_Chunk(c1,2); +} + +void +Bios_Limit_Chunk(struct chunk *c1, u_long limit) +{ + if (c1->part) + Bios_Limit_Chunk(c1->part,limit); + if (c1->next) + Bios_Limit_Chunk(c1->next,limit); + if (c1->end >= limit) { + c1->flags |= CHUNK_PAST_1024; + } else { + c1->flags &= ~CHUNK_PAST_1024; + } +} + +int +Delete_Chunk(struct disk *d, struct chunk *c) +{ + struct chunk *c1=0,*c2,*c3; + chunk_e type = c->type; + + if(type == whole) + return 1; + if(!c1 && (type == freebsd || type == fat || type == unknown)) + c1 = Find_Mother_Chunk(d->chunks,c->offset,c->end,extended); + if(!c1 && (type == freebsd || type == fat || type == unknown)) + c1 = Find_Mother_Chunk(d->chunks,c->offset,c->end,whole); + if(!c1 && type == extended) + c1 = Find_Mother_Chunk(d->chunks,c->offset,c->end,whole); + if(!c1 && type == part) + c1 = Find_Mother_Chunk(d->chunks,c->offset,c->end,freebsd); + if(!c1) + return 1; + for(c2=c1->part;c2;c2=c2->next) { + if (c2 == c) { + c2->type = unused; + c2->subtype = 0; + c2->flags = 0; + free(c2->name); + c2->name = strdup("-"); + Free_Chunk(c2->part); + c2->part =0; + goto scan; + } + } + return 1; + scan: + for(c2=c1->part;c2;c2=c2->next) { + if (c2->type != unused) + continue; + if (!c2->next) + continue; + if (c2->next->type != unused) + continue; + c3 = c2->next; + c2->size += c3->size; + c2->end = c3->end; + c2->next = c3->next; + c3->next = 0; + Free_Chunk(c3); + goto scan; + } + Fixup_Names(d); + return 0; +} + +#if 0 +int +Collapse_Chunk(struct disk *d, struct chunk *c1) +{ + struct chunk *c2, *c3; + + if(c1->next && Collapse_Chunk(d,c1->next)) + return 1; + + if(c1->type == unused && c1->next && c1->next->type == unused) { + c3 = c1->next; + c1->size += c3->size; + c1->end = c3->end; + c1->next = c3->next; + c3->next = 0; + Free_Chunk(c3); + return 1; + } + c3 = c1->part; + if(!c3) + return 0; + if (Collapse_Chunk(d,c1->part)) + return 1; + + if (c1->type == whole) + return 0; + + if(c3->type == unused && c3->size == c1->size) { + Delete_Chunk(d,c1); + return 1; + } + if(c3->type == unused) { + c2 = new_chunk(); + if (!c2) err(1,"malloc failed"); + *c2 = *c1; + c1->next = c2; + c1->disk = d; + c1->name = strdup("-"); + c1->part = 0; + c1->type = unused; + c1->flags = 0; + c1->subtype = 0; + c1->size = c3->size; + c1->end = c3->end; + c2->offset += c1->size; + c2->size -= c1->size; + c2->part = c3->next; + c3->next = 0; + Free_Chunk(c3); + return 1; + } + for(c2=c3;c2->next;c2 = c2->next) + c3 = c2; + if (c2 && c2->type == unused) { + c3->next = 0; + c2->next = c1->next; + c1->next = c2; + c1->size -= c2->size; + c1->end -= c2->size; + return 1; + } + + return 0; +} +#endif diff --git a/lib/libdisk/create_chunk.c b/lib/libdisk/create_chunk.c new file mode 100644 index 0000000..47b1e41 --- /dev/null +++ b/lib/libdisk/create_chunk.c @@ -0,0 +1,396 @@ +/* + * ---------------------------------------------------------------------------- + * "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 <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/disklabel.h> +#include <sys/diskslice.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <err.h> +#include <grp.h> +#include <pwd.h> +#include "libdisk.h" + +/* Clone these two from sysinstall because we need our own copies + * due to link order problems with `crunch'. Feh! + */ +static int +isDebug() +{ + static int debug = 0; /* Allow debugger to tweak it */ + + return debug; +} + +/* Write something to the debugging port */ +static void +msgDebug(char *fmt, ...) +{ + va_list args; + char *dbg; + static int DebugFD = -1; + + if (DebugFD == -1) + DebugFD = open("/dev/ttyv1", O_RDWR); + dbg = (char *)alloca(FILENAME_MAX); + strcpy(dbg, "DEBUG: "); + va_start(args, fmt); + vsnprintf((char *)(dbg + strlen(dbg)), FILENAME_MAX, fmt, args); + va_end(args); + write(DebugFD, dbg, strlen(dbg)); +} + +void +Fixup_FreeBSD_Names(struct disk *d, struct chunk *c) +{ + struct chunk *c1, *c3; + int j; + + if (!strcmp(c->name, "X")) return; + + /* reset all names to "X" */ + for (c1 = c->part; c1 ; c1 = c1->next) { + c1->oname = c1->name; + c1->name = malloc(12); + if(!c1->name) err(1,"Malloc failed"); + strcpy(c1->name,"X"); + } + + /* Allocate the first swap-partition we find */ + for (c1 = c->part; c1 ; c1 = c1->next) { + if (c1->type == unused) continue; + if (c1->subtype != FS_SWAP) continue; + sprintf(c1->name,"%s%c",c->name,SWAP_PART+'a'); + break; + } + + /* Allocate the first root-partition we find */ + for (c1 = c->part; c1 ; c1 = c1->next) { + if (c1->type == unused) continue; + if (!(c1->flags & CHUNK_IS_ROOT)) continue; + sprintf(c1->name,"%s%c",c->name,0+'a'); + break; + } + + /* Try to give them the same as they had before */ + for (c1 = c->part; c1 ; c1 = c1->next) { + if (strcmp(c1->name,"X")) continue; + for(c3 = c->part; c3 ; c3 = c3->next) + if (c1 != c3 && !strcmp(c3->name, c1->oname)) { + goto newname; + } + strcpy(c1->name,c1->oname); + newname: + } + + + /* Allocate the rest sequentially */ + for (c1 = c->part; c1 ; c1 = c1->next) { + const char order[] = "efghabd"; + if (c1->type == unused) continue; + if (strcmp("X",c1->name)) continue; + + for(j=0;j<strlen(order);j++) { + sprintf(c1->name,"%s%c",c->name,order[j]); + for(c3 = c->part; c3 ; c3 = c3->next) + if (c1 != c3 && !strcmp(c3->name, c1->name)) + goto match; + break; + match: + strcpy(c1->name,"X"); + continue; + } + } + for (c1 = c->part; c1 ; c1 = c1->next) { + free(c1->oname); + c1->oname = 0; + } +} + +void +Fixup_Extended_Names(struct disk *d, struct chunk *c) +{ + struct chunk *c1; + int j=5; + + for (c1 = c->part; c1 ; c1 = c1->next) { + if (c1->type == unused) continue; + free(c1->name); + c1->name = malloc(12); + if(!c1->name) err(1,"malloc failed"); + sprintf(c1->name,"%ss%d",d->chunks->name,j++); + if (c1->type == freebsd) + Fixup_FreeBSD_Names(d,c1); + } +} + +void +Fixup_Names(struct disk *d) +{ + struct chunk *c1, *c2, *c3; + int i,j; + + c1 = d->chunks; + for(i=1,c2 = c1->part; c2 ; c2 = c2->next) { + c2->flags &= ~CHUNK_BSD_COMPAT; + if (c2->type == unused) + continue; + if (strcmp(c2->name,"X")) + continue; +#ifndef __alpha__ + c2->oname = malloc(12); + if(!c2->oname) err(1,"malloc failed"); + for(j=1;j<=NDOSPART;j++) { + sprintf(c2->oname,"%ss%d",c1->name,j); + for(c3 = c1->part; c3 ; c3 = c3->next) + if (c3 != c2 && !strcmp(c3->name, c2->oname)) + goto match; + free(c2->name); + c2->name = c2->oname; + c2->oname = 0; + break; + match: + continue; + } + if (c2->oname) + free(c2->oname); +#else + free(c2->name); + c2->name = strdup(c1->name); +#endif + } + for(c2 = c1->part; c2 ; c2 = c2->next) { + if (c2->type == freebsd) { + c2->flags |= CHUNK_BSD_COMPAT; + break; + } + } + for(c2 = c1->part; c2 ; c2 = c2->next) { + if (c2->type == freebsd) + Fixup_FreeBSD_Names(d,c2); + if (c2->type == extended) + Fixup_Extended_Names(d,c2); + } +} + +int +Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, int subtype, u_long flags) +{ + int i; + u_long l; + + if(!(flags & CHUNK_FORCE_ALL)) + { + /* Never use the first track */ + if (!offset) { + offset += d->bios_sect; + size -= d->bios_sect; + } + + /* Always end on cylinder boundary */ + l = (offset+size) % (d->bios_sect * d->bios_hd); + size -= l; + } + + i = Add_Chunk(d,offset,size,"X",type,subtype,flags); + Fixup_Names(d); + return i; +} + +struct chunk * +Create_Chunk_DWIM(struct disk *d, struct chunk *parent , u_long size, chunk_e type, int subtype, u_long flags) +{ + int i; + struct chunk *c1; + u_long offset; + + if (!parent) + parent = d->chunks; + for (c1=parent->part; c1 ; c1 = c1->next) { + if (c1->type != unused) continue; + if (c1->size < size) continue; + offset = c1->offset; + goto found; + } + return 0; + found: + i = Add_Chunk(d,offset,size,"X",type,subtype,flags); + if (i) + return 0; + Fixup_Names(d); + for (c1=parent->part; c1 ; c1 = c1->next) + if (c1->offset == offset) + return c1; + err(1,"Serious internal trouble"); +} + +int +MakeDev(struct chunk *c1, const char *path) +{ + char *p = c1->name; + u_long cmaj, min, unit, part, slice; + char buf[BUFSIZ], buf2[BUFSIZ]; + struct group *grp; + struct passwd *pwd; + + *buf2 = '\0'; + if (isDebug()) + msgDebug("MakeDev: Called with %s on path %s\n", p, path); + if (!strcmp(p, "X")) + return 0; + + if (!strncmp(p, "wd", 2)) + cmaj = 3, p += 2; + else if (!strncmp(p, "ad", 2)) + cmaj = 116, p += 2; + else if (!strncmp(p, "wfd", 3)) + cmaj = 87, p += 3; + else if (!strncmp(p, "afd", 3)) + cmaj = 118, p += 3; + else if (!strncmp(p, "fla", 3)) + cmaj = 102, p += 3; + else if (!strncmp(p, "ida", 3)) + cmaj = 109, p += 3; + else if (!strncmp(p, "mlxd", 4)) + cmaj = 131, p += 4; + else if (!strncmp(p, "amrd", 4)) + cmaj = 133, p += 4; + else if (!strncmp(p, "da", 2)) /* CAM support */ + cmaj = 13, p += 2; + else { + msgDebug("MakeDev: Unknown major/minor for devtype %s\n", p); + return 0; + } + if (!isdigit(*p)) { + msgDebug("MakeDev: Invalid disk unit passed: %s\n", p); + return 0; + } + unit = *p - '0'; + p++; + if (!*p) { + slice = 1; + part = 2; + goto done; + } + else if (isdigit(*p)) { + unit *= 10; + unit += (*p - '0'); + p++; + } +#ifndef __alpha__ + if (*p != 's') { + msgDebug("MakeDev: `%s' is not a valid slice delimiter\n", p); + return 0; + } + p++; + if (!isdigit(*p)) { + msgDebug("MakeDev: `%s' is an invalid slice number\n", p); + return 0; + } + slice = *p - '0'; + p++; + if (isdigit(*p)) { + slice *= 10; + slice += (*p - '0'); + p++; + } + slice = slice + 1; +#else + slice = 0; +#endif + if (!*p) { + part = 2; + if(c1->type == freebsd) + sprintf(buf2, "%sc", c1->name); + goto done; + } + if (*p < 'a' || *p > 'h') { + msgDebug("MakeDev: `%s' is not a valid partition name.\n", p); + return 0; + } + part = *p - 'a'; + done: + if (isDebug()) + msgDebug("MakeDev: Unit %d, Slice %d, Part %d\n", unit, slice, part); + if (unit > 32) + return 0; + if (slice > 32) + return 0; + if ((pwd = getpwnam("root")) == NULL) { + msgDebug("MakeDev: Unable to lookup user \"root\".\n"); + return 0; + } + if ((grp = getgrnam("operator")) == NULL) { + msgDebug("MakeDev: Unable to lookup group \"operator\".\n"); + return 0; + } + min = unit * 8 + 65536 * slice + part; + sprintf(buf, "%s/r%s", path, c1->name); + unlink(buf); + if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) { + msgDebug("mknod of %s returned failure status!\n", buf); + return 0; + } + if (chown(buf, pwd->pw_uid, grp->gr_gid) == -1) { + msgDebug("chown of %s returned failure status!\n", buf); + return 0; + } + if (*buf2) { + sprintf(buf, "%s/r%s", path, buf2); + unlink(buf); + if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) { + msgDebug("mknod of %s returned failure status!\n", buf); + return 0; + } + if (chown(buf, pwd->pw_uid, grp->gr_gid) == -1) { + msgDebug("chown of %s returned failure status!\n", buf); + return 0; + } + } + sprintf(buf, "%s/%s", path, c1->name); + unlink(buf); + if (mknod(buf, S_IFCHR|0640, makedev(cmaj,min)) == -1) { + msgDebug("mknod of %s returned failure status!\n", buf); + return 0; + } + if (chown(buf, pwd->pw_uid, grp->gr_gid) == -1) { + msgDebug("chown of %s returned failure status!\n", buf); + return 0; + } + return 1; +} + +int +MakeDevChunk(struct chunk *c1, const char *path) +{ + int i; + + i = MakeDev(c1, path); + if (c1->next) + MakeDevChunk(c1->next, path); + if (c1->part) + MakeDevChunk(c1->part, path); + return i; +} + +int +MakeDevDisk(struct disk *d, const char *path) +{ + return MakeDevChunk(d->chunks, path); +} 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"; + } +} diff --git a/lib/libdisk/disklabel.c b/lib/libdisk/disklabel.c new file mode 100644 index 0000000..2ee6503 --- /dev/null +++ b/lib/libdisk/disklabel.c @@ -0,0 +1,33 @@ +/* + * ---------------------------------------------------------------------------- + * "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 <err.h> +#include <sys/disklabel.h> +#include "libdisk.h" + +struct disklabel * +read_disklabel(int fd, daddr_t block) +{ + struct disklabel *dp; + + dp = (struct disklabel *) read_block(fd,block); + if (dp->d_magic != DISKMAGIC) + return 0; + if (dp->d_magic2 != DISKMAGIC) + return 0; + if (dkcksum(dp) != 0) + return 0; + return dp; +} diff --git a/lib/libdisk/libdisk.3 b/lib/libdisk/libdisk.3 new file mode 100644 index 0000000..07c1ffe --- /dev/null +++ b/lib/libdisk/libdisk.3 @@ -0,0 +1,331 @@ +.\" +.\" Copyright (c) 1996 Joerg Wunsch +.\" +.\" All rights reserved. +.\" +.\" This program is free software. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" " +.Dd March 15, 1996 +.Dt LIBDISK 3 +.Os +.Sh NAME +.Nm Open_Disk , +.Nm Clone_Disk , +.Nm Free_Disk , +.Nm Debug_Disk , +.Nm Set_Bios_Geom , +.Nm Delete_Chunk , +.Nm Collapse_Disk , +.Nm Collapse_Chunk , +.Nm Create_Chunk , +.Nm All_FreeBSD , +.Nm CheckRules , +.Nm Disk_Names , +.Nm Set_Boot_Mgr , +.Nm Set_Boot_Blocks , +.Nm Write_Disk , +.Nm Cyl_Aligned , +.Nm Next_Cyl_Aligned , +.Nm Prev_Cyl_Aligned , +.Nm Track_Aligned , +.Nm Next_Track_Aligned , +.Nm Prev_Track_Aligned , +.Nm Create_Chunk_DWIM , +.Nm MakeDev , +.Nm MakeDevDisk , +.Nm ShowChunkFlags , +.Nm ChunkCanBeRoot , +.Nm chunk_n , +.Nm slice_type_name +.Nd library interface to slice and partition labels (libdisk) +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <libdisk.h> + +.Dv extern const char *chunk_n[]; +.Ft const char * +.Fn slice_type_name "int type" "int subtype" +.Ft struct disk * +.Fn Open_Disk "const char *devname" +.Ft struct disk * +.Fn Clone_Disk "struct disk *disk" +.Ft void +.Fn Free_Disk "struct disk *disk" +.Ft void +.Fn Debug_Disk "struct disk *disk" +.Ft void +.Fn Set_Bios_Geom "struct disk *disk" "u_long cyl" "u_long heads" "u_long sects" +.Ft int +.Fn Delete_Chunk "struct disk *disk" "struct chunk *" +.Ft void +.Fn Collapse_Disk "struct disk *disk" +.Ft int +.Fn Collapse_Chunk "struct disk *disk" "struct chunk *chunk" +.Ft int +.Fn Create_Chunk "struct disk *disk" "u_long offset" "u_long size" "chunk_e type" "int subtype" "u_long flags" +.Ft void +.Fn All_FreeBSD "struct disk *d" "int force_all" +.Ft char * +.Fn CheckRules "struct disk *" +.Ft char ** +.Fn Disk_Names "void" +.Ft void +.Fn Set_Boot_Mgr "struct disk *d" "const u_char *bootmgr" +.Ft void +.Fn Set_Boot_Blocks "struct disk *d" "const u_char *boot1" "const u_char *boot2" +.Ft int +.Fn Write_Disk "struct disk *d" +.Ft int +.Fn Cyl_Aligned "struct disk *d" "u_long offset" +.Ft u_long +.Fn Next_Cyl_Aligned "struct disk *d" "u_long offset" +.Ft u_long +.Fn Prev_Cyl_Aligned "struct disk *d" "u_long offset" +.Ft int +.Fn Track_Aligned "struct disk *d" "u_long offset" +.Ft u_long +.Fn Next_Track_Aligned "struct disk *d" "u_long offset" +.Ft u_long +.Fn Prev_Track_Aligned "struct disk *d" "u_long offset" +.Ft struct chunk * +.Fn Create_Chunk_DWIM "struct disk *d" "struct chunk *parent" "u_long size" "chunk_e type" "int subtype" "u_long flags" +.Ft int +.Fn MakeDev "struct chunk *c" "const char *path" +.Ft int +.Fn MakeDevDisk "struct disk *d" "const char *path" +.Ft char * +.Fn ShowChunkFlags "struct chunk *c" +.Ft char * +.Fn ChunkCanBeRoot "struct chunk *c" +.Sh DESCRIPTION +.Nm Libdisk +provides an interface to the low-level disk slice and partition labels. +Most functions operate with arguments of the types +.Ql struct disk , +or +.Ql struct chunk . +.Pp +While both types are mostly opaque to the programmer, the internal +structure is mentioned below for the sake of completeness. +.Bd -literal -offset indent +struct disk { + char *name; + u_long flags; + u_long bios_cyl; + u_long bios_hd; + u_long bios_sect; + u_char *bootmgr; + u_char *boot1; + u_char *boot2; + struct chunk *chunks; +}; +.Ed +The only flag value by now is +.Ql DISK_ON_TRACK , +meaning that this disk is handled by the On-Track Disk Manager. +.Pp +.Bd -literal -offset indent +struct chunk { + struct chunk *next; + struct chunk *part; + struct disk *disk; + long offset; + u_long size; + u_long end; + char *name; + char *oname; + chunk_e type; + int subtype; + u_long flags; + void (*private_free)(void*); + void *(*private_clone)(void*); + void *private_data; +}; +.Ed +The +.Ql type +field can be one of the following values: +.Ql whole, unknown, fat, freebsd, extended, part, unused . +.Pp +These are the valid +.Ql flag +values for a +.Ql struct chunk . +.Bl -tag -offset indent -width CHUNK_BSD_COMPATXX +.It CHUNK_PAST_1024 +This chunk cannot be booted from because it extends past cylinder 1024. +.It CHUNK_BSD_COMPAT +This chunk is in the BSD-compatibility, and has a short name too, i.e. +.Ql wd0s4f -> wd0f . +.It CHUNK_ALIGN +This chunk should be aligned. +.It CHUNK_IS_ROOT +This +.Ql part +is a rootfs, allocate partition +.Sq a . +.It CHUNK_ACTIVE +This is the active slice in the MBR. +.It CHUNK_FORCE_ALL +Force a dedicated disk for +.Fx , +bypassing all BIOS geometry considerations. +.El +.Pp +The +.Ql private_data , +.Ql private_free , +and +.Ql private_clone +fields are for data private to the application, and the management +thereof. If the functions are not provided, no storage management is +done, cloning will just copy the pointer and freeing will just forget +it. +.Pp +.Fn Open_Disk +will open the named disk, and return populated tree. +.Pp +.Fn Clone_Disk +clones a copy of a tree. Useful for +.Dq Undo +functionality. +.Pp +.Fn Free_Disk +frees a tree made with +.Fn Open_Disk +or +.Fn Clone_Disk . +.Pp +.Fn Debug_Disk +prints the content of the tree to stdout. +.Pp +.Fn Set_Bios_Geom +sets the geometry the bios uses. +.Pp +.Fn Delete_Chunk +frees a chunk of disk_space. +.Pp +.Fn Collapse_Disk +and +.Fn Collapse_Chunk +are experimental, do not use. +.Pp +.Fn Create_Chunk +creates a chunk with the specified parameters. +.Pp +.Fn All_FreeBSD +makes one FreeBSD chunk covering the entire disk; if +.Ql force_all +is set, bypass all BIOS geometry considerations. +.Pp +.Fn CheckRules +returns +.Ql char* +to warnings about broken design rules in this disklayout. +.Pp +.Fn Disk_Names +returns +.Ql char** +with all disk's names (wd0, wd1 ...). You must free each pointer, as +well as the array by hand. +.Pp +.Fn Set_Boot_Mgr +sets this boot-manager for use on this disk. Gets written when +.Fn Write_Disk +is called. +.Pp +.Fn Set_Boot_Blocks +sets the boot-blocks for use on this disk. Gets written when +.Fn Write_Disk +is called. +.Pp +.Fn Write_Disk +writes all the MBRs, disklabels, bootblocks and boot managers. +.Pp +.Fn Cyl_Aligned +checks if +.Ql offset +is aligned on a cylinder according to the BIOS geometry. +.Pp +.Fn Next_Cyl_Aligned +rounds +.Ql offset +up to next cylinder according to the BIOS geometry. +.Pp +.Fn Prev_Cyl_Aligned +rounds +.Ql offset +down to previous cylinder according to the BIOS geometry. +.Pp +.Fn Track_Aligned +checks if +.Ql offset +is aligned on a track according to the BIOS geometry. +.Pp +.Fn Next_Track_Aligned +rounds +.Ql offset +up to next track according to the BIOS geometry. +.Pp +.Fn Prev_Track_Aligned +checks if +.Ql offset +is aligned on a track according to the BIOS geometry. +.Pp +.Fn Create_Chunk_DWIM +creates a partition inside the given parent of the given size, and +returns a pointer to it. The first unused chunk big enough is used. +.Pp +.Fn MakeDev +makes the device nodes for this chunk. +.Pp +.Fn MakeDevDisk +makes the device nodes for all chunks on this disk. +.Pp +.Fn ShowChunkFlags +returns a string to show flags. +.Pp +.Fn ChunkCanBeRoot +returns NULL if chunk can be +.Pp +Chunk name strings can be accessed directly using the external array +.Va chunk_n . +.Pp +.Fn slice_type_name +returns the name strings associated with the specified +.Ql type . +.Ql subtype . +If +.Fn slice_type_name +returns "unknown" for slices it isn't familiar with. +.Ql / . +.Sh AUTHORS +.Nm Libdisk +has been written by +.An Poul-Henning Kamp . +.Pp +This man page by +.ie t J\(:org Wunsch. +.el Joerg Wunsch. diff --git a/lib/libdisk/libdisk.h b/lib/libdisk/libdisk.h new file mode 100644 index 0000000..bf9eff1 --- /dev/null +++ b/lib/libdisk/libdisk.h @@ -0,0 +1,325 @@ +/* +* ---------------------------------------------------------------------------- +* "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$ +* +*/ + +#define MAX_NO_DISKS 20 +/* Max # of disks Disk_Names() will return */ + +typedef enum { + whole, + unknown, + fat, + freebsd, + extended, + part, + unused +} chunk_e; + +__BEGIN_DECLS +struct disk { + char *name; + u_long flags; +# define DISK_ON_TRACK 1 + u_long bios_cyl; + u_long bios_hd; + u_long bios_sect; + u_char *bootmgr; + u_char *boot1; +#if defined(__i386__) /* the alpha only has one boot program */ + u_char *boot2; +#endif + struct chunk *chunks; +}; + +struct chunk { + struct chunk *next; + struct chunk *part; + struct disk *disk; + long offset; + u_long size; + u_long end; + char *name; + char *oname; + /* Used during Fixup_Names() to avoid renaming more than + * absolutely needed. + */ + chunk_e type; + int subtype; + u_long flags; +# define CHUNK_PAST_1024 1 + /* this chunk cannot be booted from because it + * extends past cylinder 1024 + */ +# define CHUNK_BSD_COMPAT 2 + /* this chunk is in the BSD-compatibility, and has a + * short name too, ie wd0s4f -> wd0f + */ +# define CHUNK_ALIGN 8 + /* This chunk should be aligned */ +# define CHUNK_IS_ROOT 16 + /* This 'part' is a rootfs, allocate 'a' */ +# define CHUNK_ACTIVE 32 + /* This is the active slice in the MBR */ +# define CHUNK_FORCE_ALL 64 + /* Force a dedicated disk for FreeBSD, bypassing + * all BIOS geometry considerations + */ + + void (*private_free)(void*); + void *(*private_clone)(void*); + void *private_data; + /* For data private to the application, and the management + * thereof. If the functions are not provided, no storage + * management is done, Cloning will just copy the pointer + * and freeing will just forget it. + */ +}; + +extern const char *chunk_n[]; + +const char * +slice_type_name( int type, int subtype ); +/* "chunk_n" for subtypes too + */ + +struct disk * +Open_Disk(const char *devname); +/* Will open the named disk, and return populated tree. + */ + +struct disk * +Clone_Disk(struct disk *disk); +/* Clone a copy of a tree. Useful for "Undo" functionality + */ + +void +Free_Disk(struct disk *disk); +/* Free a tree made with Open_Disk() or Clone_Disk() + */ + +void +Debug_Disk(struct disk *disk); +/* Print the content of the tree to stdout + */ + +void +Set_Bios_Geom(struct disk *disk, u_long cyl, u_long heads, u_long sects); +/* Set the geometry the bios uses. + */ + +void +Sanitize_Bios_Geom(struct disk *disk); +/* Set the bios geometry to something sane + */ + +int +Delete_Chunk(struct disk *disk, struct chunk *); +/* Free a chunk of disk_space + */ + +void +Collapse_Disk(struct disk *disk); +/* Experimental, do not use. + */ +int +Collapse_Chunk(struct disk *disk, struct chunk *chunk); +/* Experimental, do not use. + */ + +int +Create_Chunk(struct disk *disk, u_long offset, u_long size, chunk_e type, + int subtype, u_long flags); +/* Create a chunk with the specified paramters + */ + +void +All_FreeBSD(struct disk *d, int force_all); +/* Make one FreeBSD chunk covering the entire disk; + * if force_all is set, bypass all BIOS geometry + * considerations. + */ + +char * +CheckRules(struct disk *); +/* Return char* to warnings about broken design rules in this disklayout + */ + +char ** +Disk_Names(); +/* Return char** with all disk's names (wd0, wd1 ...). You must free + * each pointer, as well as the array by hand + */ + +void +Set_Boot_Mgr(struct disk *d, const u_char *bootmgr); +/* Use this boot-manager on this disk. Gets written when Write_Disk() + * is called + */ + +void +Set_Boot_Blocks(struct disk *d, const u_char *_boot1, const u_char *_boot2); +/* Use these boot-blocks on this disk. Gets written when Write_Disk() + * is called + */ + +int +Write_Disk(struct disk *d); +/* Write all the MBRs, disklabels, bootblocks and boot managers + */ + +int +Cyl_Aligned(struct disk *d, u_long offset); +/* Check if offset is aligned on a cylinder according to the + * bios geometry + */ + +u_long +Next_Cyl_Aligned(struct disk *d, u_long offset); +/* Round offset up to next cylinder according to the bios-geometry + */ + +u_long +Prev_Cyl_Aligned(struct disk *d, u_long offset); +/* Round offset down to previous cylinder according to the bios- + * geometry + */ + +int +Track_Aligned(struct disk *d, u_long offset); +/* Check if offset is aligned on a track according to the + * bios geometry + */ + +u_long +Next_Track_Aligned(struct disk *d, u_long offset); +/* Round offset up to next track according to the bios-geometry + */ + +u_long +Prev_Track_Aligned(struct disk *d, u_long offset); +/* Check if offset is aligned on a track according to the + * bios geometry + */ + +struct chunk * +Create_Chunk_DWIM(struct disk *d, struct chunk *parent , u_long size, + chunk_e type, int subtype, u_long flags); +/* This one creates a partition inside the given parent of the given + * size, and returns a pointer to it. The first unused chunk big + * enough is used. + */ + +int +MakeDev(struct chunk *c, const char *path); + +int +MakeDevDisk(struct disk *d, const char *path); +/* Make device nodes for all chunks on this disk */ + +char * +ShowChunkFlags(struct chunk *c); +/* Return string to show flags. */ + +char * +ChunkCanBeRoot(struct chunk *c); +/* Return NULL if chunk can be /, explanation otherwise */ + +/* + * Implementation details >>> DO NOT USE <<< + */ + +void Debug_Chunk(struct chunk *); +void Free_Chunk(struct chunk *); +struct chunk * Clone_Chunk(struct chunk *); +int Add_Chunk(struct disk *, long, u_long, const char *, chunk_e, int, u_long); +void Bios_Limit_Chunk(struct chunk *, u_long); +void * read_block(int, daddr_t); +void write_block(int fd, daddr_t block, void *foo); +struct disklabel * read_disklabel(int, daddr_t); +u_short dkcksum(struct disklabel *); +struct chunk * Find_Mother_Chunk(struct chunk *, u_long, u_long, chunk_e); +struct disk * Int_Open_Disk(const char *name, u_long size); +void Fixup_Names(struct disk *); +__END_DECLS + +#define dprintf printf + +/* TODO + * + * Need a error string mechanism from the functions instead of warn() + * + * Make sure only FreeBSD start at offset==0 + * + * Collapse must align. + * + * Make Write_Disk(struct disk*) + * + * Consider booting from OnTrack'ed disks. + * + * Get Bios-geom, ST506 & OnTrack from driver (or otherwise) + * + * Make Create_DWIM(). + * + * Make Is_Unchanged(struct disk *d1, struct chunk *c1) + * + * don't rename slices unless we have to + * + *Sample output from tst01: + * + * Debug_Disk(wd0) flags=0 bios_geom=0/0/0 + * >> 0x3d040 0 1411200 1411199 wd0 0 whole 0 0 + * >>>> 0x3d080 0 960120 960119 wd0s1 3 freebsd 0 8 + * >>>>>> 0x3d100 0 40960 40959 wd0s1a 5 part 0 0 + * >>>>>> 0x3d180 40960 131072 172031 wd0s1b 5 part 0 0 + * >>>>>> 0x3d1c0 172032 409600 581631 wd0s1e 5 part 0 0 + * >>>>>> 0x3d200 581632 378488 960119 wd0s1f 5 part 0 0 + * >>>> 0x3d140 960120 5670 965789 wd0s2 4 extended 0 8 + * >>>>>> 0x3d2c0 960120 63 960182 - 6 unused 0 0 + * >>>>>> 0x3d0c0 960183 5607 965789 wd0s5 2 fat 0 8 + * >>>> 0x3d280 965790 1890 967679 wd0s3 1 foo -2 8 + * >>>> 0x3d300 967680 443520 1411199 wd0s4 3 freebsd 0 8 + * >>>>>> 0x3d340 967680 443520 1411199 wd0s4a 5 part 0 0 + * + * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ + * level chunkptr start size end name type subtype flags + * + * Underlying data structure: + * + * Legend: + * <struct chunk> --> part + * | + * v next + * + * <wd0> --> <wd0s1> --> <wd0s1a> + * | | + * | v + * | <wd0s1b> + * | | + * | v + * | <wd0s1e> + * | | + * | v + * | <wd0s1f> + * | + * v + * <wd0s2> --> <unused> + * | | + * | v + * | <wd0s5> + * | + * v + * <wd0s3> + * | + * v + * <wd0s4> --> <wd0s4a> + * + * + */ diff --git a/lib/libdisk/rules.c b/lib/libdisk/rules.c new file mode 100644 index 0000000..fcc3d3b --- /dev/null +++ b/lib/libdisk/rules.c @@ -0,0 +1,285 @@ +/* + * ---------------------------------------------------------------------------- + * "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 <string.h> +#include <sys/types.h> +#include <sys/diskslice.h> +#include <sys/disklabel.h> +#include <err.h> +#include "libdisk.h" + +int +Track_Aligned(struct disk *d, u_long offset) +{ + if (!d->bios_sect) + return 1; + if (offset % d->bios_sect) + return 0; + return 1; +} + +u_long +Prev_Track_Aligned(struct disk *d, u_long offset) +{ + if (!d->bios_sect) + return offset; + return (offset / d->bios_sect) * d->bios_sect; +} + +u_long +Next_Track_Aligned(struct disk *d, u_long offset) +{ + if (!d->bios_sect) + return offset; + return Prev_Track_Aligned(d,offset + d->bios_sect-1); +} + +int +Cyl_Aligned(struct disk *d, u_long offset) +{ + if (!d->bios_sect || !d->bios_hd) + return 1; + if (offset % (d->bios_sect * d->bios_hd)) + return 0; + return 1; +} + +u_long +Prev_Cyl_Aligned(struct disk *d, u_long offset) +{ + if (!d->bios_sect || !d->bios_hd) + return offset; + return (offset / (d->bios_sect*d->bios_hd)) * d->bios_sect * d->bios_hd; +} + +u_long +Next_Cyl_Aligned(struct disk *d, u_long offset) +{ + if (!d->bios_sect || !d->bios_hd) + return offset; + return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd)-1); +} + +/* + * Rule#0: + * Chunks of type 'whole' can have max NDOSPART children. + * Only one of them can have the "active" flag + */ +void +Rule_000(struct disk *d, struct chunk *c, char *msg) +{ + int i=0,j=0; + struct chunk *c1; + + if (c->type != whole) + return; + for (c1=c->part; c1; c1=c1->next) { + if (c1->type != unused) continue; + if (c1->flags & CHUNK_ACTIVE) + j++; + i++; + } + if (i > NDOSPART) + sprintf(msg+strlen(msg), + "%d is too many children of the 'whole' chunk. Max is %d\n", + i, NDOSPART); + if (j > 1) + sprintf(msg+strlen(msg), + "Too many active children of 'whole'"); +} + +/* + * Rule#1: + * All children of 'whole' and 'extended' must be track-aligned. + * Exception: the end can be unaligned if it matches the end of 'whole' + */ +void +Rule_001(struct disk *d, struct chunk *c, char *msg) +{ + int i; + struct chunk *c1; + + if (c->type != whole && c->type != extended) + return; + for (i=0, c1=c->part; c1; c1=c1->next) { + if (c1->type == unused) continue; + c1->flags |= CHUNK_ALIGN; + if (!Track_Aligned(d,c1->offset)) + sprintf(msg+strlen(msg), + "chunk '%s' [%ld..%ld] does not start on a track boundary\n", + c1->name,c1->offset,c1->end); + if ((c->type == whole || c->end == c1->end) + || Cyl_Aligned(d,c1->end+1)) + ; + else + sprintf(msg+strlen(msg), + "chunk '%s' [%ld..%ld] does not end on a cylinder boundary\n", + c1->name,c1->offset,c1->end); + } +} + +/* + * Rule#2: + * Max one 'fat' as child of 'whole' + */ +void +Rule_002(struct disk *d, struct chunk *c, char *msg) +{ + int i; + struct chunk *c1; + + if (c->type != whole) + return; + for (i=0, c1=c->part; c1; c1=c1->next) { + if (c1->type != fat) + continue; + i++; + } + if (i > 1) { + sprintf(msg+strlen(msg), + "Max one 'fat' allowed as child of 'whole'\n"); + } +} + +/* + * Rule#3: + * Max one extended as child of 'whole' + */ +void +Rule_003(struct disk *d, struct chunk *c, char *msg) +{ + int i; + struct chunk *c1; + + if (c->type != whole) + return; + for (i=0, c1=c->part; c1; c1=c1->next) { + if (c1->type != extended) + continue; + i++; + } + if (i > 1) { + sprintf(msg+strlen(msg), + "Max one 'extended' allowed as child of 'whole'\n"); + } +} + +/* + * Rule#4: + * Max seven 'part' as children of 'freebsd' + * Max one CHUNK_IS_ROOT child per 'freebsd' + * If Bad144, space for table must exist. + * If Bad144 & root, bad144 table must be inside 1024 + */ +void +Rule_004(struct disk *d, struct chunk *c, char *msg) +{ + int i=0,k=0; + struct chunk *c1; + + if (c->type != freebsd) + return; + + for (c1=c->part; c1; c1=c1->next) { + if (c1->type != part) + continue; + if (c1->flags & CHUNK_IS_ROOT) { + k++; + if (c1->flags & CHUNK_PAST_1024) + sprintf(msg+strlen(msg), + "Root filesystem extends past cylinder 1024, and cannot be booted from\n"); + } + i++; + } + if (i > 7) { + sprintf(msg+strlen(msg), + "Max seven partitions per freebsd slice\n"); + } + if (k > 1) { + sprintf(msg+strlen(msg), + "Max one root partition child per freebsd slice\n"); + } +} + +void +Check_Chunk(struct disk *d, struct chunk *c, char *msg) +{ + Rule_000(d,c,msg); + Rule_001(d,c,msg); + Rule_002(d,c,msg); + Rule_003(d,c,msg); + Rule_004(d,c,msg); + if (c->part) + Check_Chunk(d,c->part,msg); + if (c->next) + Check_Chunk(d,c->next,msg); + + if (c->end >= 1024*d->bios_hd*d->bios_sect) + c->flags |= CHUNK_PAST_1024; + else + c->flags &= ~CHUNK_PAST_1024; +} + +char * +CheckRules(struct disk *d) +{ + char msg[BUFSIZ]; + + *msg = '\0'; + Check_Chunk(d,d->chunks,msg); + if (*msg) + return strdup(msg); + return 0; +} + +char * +ChunkCanBeRoot(struct chunk *c) +{ + struct chunk *c1; + struct disk *d = c->disk; + char msg[BUFSIZ]; + + *msg = '\0'; + if (c->flags & CHUNK_PAST_1024) { + strcat(msg, +"The root partition must end before cylinder 1024 seen from\n"); + strcat(msg, +"the BIOS' point of view, or it cannot be booted from.\n"); + return strdup(msg); + } + for (c1=d->chunks->part;;) { + for (; c1; c1=c1->next) + if (c1->offset <= c->offset && c1->end >= c->end) + break; + if (!c1) { + strcat(msg, +"Internal trouble, cannot find this chunk in the chunk-tree\n"); + return strdup(msg); + } + if (c1->type == freebsd) + break; + c1 = c1->part; + } + + if (c1->type != freebsd) { + strcat(msg, +"The root partition must be in a FreeBSD slice, otherwise\n"); + strcat(msg, +"the kernel cannot be booted from it\n"); + return strdup(msg); + } + + return NULL; +} diff --git a/lib/libdisk/tst01.c b/lib/libdisk/tst01.c new file mode 100644 index 0000000..e8c34d9 --- /dev/null +++ b/lib/libdisk/tst01.c @@ -0,0 +1,298 @@ +/* + * ---------------------------------------------------------------------------- + * "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> +#ifdef READLINE +#include <readline/readline.h> +#include <readline/history.h> +#endif +#include <sys/types.h> +#include "libdisk.h" + +u_char mbr[] = { +250,51,192,142,208,188,0,124,139,244,80,7,80,31,251,252,191,0,6,185,0,1, +242,165,234,29,6,0,0,190,190,7,179,4,128,60,128,116,14,128,60,0,117,28, +131,198,16,254,203,117,239,205,24,139,20,139,76,2,139,238,131,198,16,254, +203,116,26,128,60,0,116,244,190,139,6,172,60,0,116,11,86,187,7,0,180,14, +205,16,94,235,240,235,254,191,5,0,187,0,124,184,1,2,87,205,19,95,115,12, +51,192,205,19,79,117,237,190,163,6,235,211,190,194,6,191,254,125,129,61, +85,170,117,199,139,245,234,0,124,0,0,73,110,118,97,108,105,100,32,112,97, +114,116,105,116,105,111,110,32,116,97,98,108,101,0,69,114,114,111,114,32, +108,111,97,100,105,110,103,32,111,112,101,114,97,116,105,110,103,32,115, +121,115,116,101,109,0,77,105,115,115,105,110,103,32,111,112,101,114,97, +116,105,110,103,32,115,121,115,116,101,109,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128, +1,1,0,4,15,63,60,63,0,0,0,241,239,0,0,0,0,1,61,5,15,63,243,48,240,0,0,144, +208,2,0,0,0,1,244,165,15,63,170,192,192,3,0,144,208,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,85,170 +}; + +u_char bteasy17[] = { +51,192,142,192,142,216,142,208,188,0,124,252,139,244,191,0,6,185,0,1,242, +165,234,96,6,0,0,139,213,88,162,72,7,60,53,116,28,180,16,246,228,5,174, +4,150,246,68,4,255,116,62,198,4,128,232,218,0,138,116,1,139,76,2,235,8, +232,207,0,185,1,0,50,209,187,0,124,184,1,2,205,19,114,30,129,191,254,1, +85,170,117,22,234,0,124,0,0,128,250,129,116,2,178,128,139,234,66,128,242, +179,136,22,58,7,191,190,7,185,4,0,198,6,45,7,49,50,246,136,45,138,69,4, +60,0,116,35,60,5,116,31,254,198,190,42,7,232,113,0,190,72,7,70,70,139,28, +10,255,116,5,50,125,4,117,243,141,183,114,7,232,90,0,131,199,16,254,6,45, +7,226,203,128,62,117,4,2,116,11,190,59,7,10,246,117,10,205,24,235,172,190, +42,7,232,57,0,232,54,0,50,228,205,26,139,218,131,195,96,180,1,205,22,180, +0,117,11,205,26,59,211,114,242,160,72,7,235,10,205,22,138,196,60,28,116, +243,4,246,60,49,114,214,60,53,119,210,80,190,40,7,187,27,6,83,252,172,80, +36,127,180,14,205,16,88,168,128,116,242,195,86,184,1,3,187,0,6,185,1,0, +50,246,205,19,94,198,6,72,7,63,195,13,138,13,10,70,48,32,46,32,46,32,46, +160,100,105,115,107,32,49,13,10,10,68,101,102,97,117,108,116,58,32,70,63, +160,0,1,0,4,0,6,3,7,7,10,10,99,14,100,14,101,20,128,20,129,25,130,30,147, +36,165,39,159,43,117,47,82,47,219,50,64,55,242,61,0,100,111,243,72,80,70, +211,79,115,178,85,110,105,248,78,111,118,101,108,236,77,105,110,105,248, +76,105,110,117,248,65,109,111,101,98,225,66,83,196,66,83,68,233,80,67,73, +216,67,80,205,86,101,110,105,248,68,111,115,115,101,227,63,191,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,85,170 +}; + +int +scan_block(int fd, daddr_t block) +{ + u_char foo[512]; + + if (-1 == lseek(fd, (off_t)block * 512, SEEK_SET)) + err(1, "lseek"); + if (512 != read(fd,foo, 512)) + return 1; + return 0; +} + +void +Scan_Disk(struct disk *d) +{ + char device[64]; + u_long l; + int i,j,fd; + + strcpy(device,"/dev/r"); + strcat(device,d->name); + + fd = open(device,O_RDWR); + if (fd < 0) { + warn("open(%s) failed",device); + return; + } + for(i=-1,l=0;;l++) { + j = scan_block(fd,l); + if (j != i) { + if (i == -1) { + printf("%c: %lu.",j ? 'B' : 'G', l); + fflush(stdout); + } else if (i == 0) { + printf(".%lu\nB: %lu.",l-1,l); + fflush(stdout); + } else { + printf(".%lu\nG: %lu.",l-1,l); + fflush(stdout); + } + i = j; + } + } + close(fd); +} + +int +main(int argc, char **argv) +{ + struct disk *d,*db; + char myprompt[BUFSIZ]; +#ifndef READLINE + char input[BUFSIZ]; +#endif + char *p,*q=0; + char **cp,*cmds[200]; + int ncmd,i; + + if (argc < 2) { + fprintf(stderr,"Usage:\n\t%s diskname\n",argv[0]); + exit(1); + } + d = Open_Disk(argv[1]); + if (!d) + err(1,"Couldn't open disk %s",argv[1]); + + sprintf(myprompt,"%s %s> ",argv[0],argv[1]); + while(1) { + printf("--==##==--\n"); + p = CheckRules(d); + Debug_Disk(d); + if (p) { + printf("%s",p); + free(p); + } +#ifdef READLINE + if (q) + free(q); + q = p = readline(myprompt); +#else + printf(myprompt); + fflush(stdout); + q = p = fgets(input,sizeof(input),stdin); +#endif + if(!p) + break; + for(cp = cmds; (*cp = strsep(&p, " \t\n")) != NULL;) + if (**cp != '\0') + cp++; + ncmd = cp - cmds; + if(!ncmd) + continue; + if (!strcasecmp(*cmds,"quit")) { break; } + if (!strcasecmp(*cmds,"exit")) { break; } + if (!strcasecmp(*cmds,"q")) { break; } + if (!strcasecmp(*cmds,"x")) { break; } + if (!strcasecmp(*cmds,"dwim") && ncmd == 6) { + printf("dwim = %p\n", + Create_Chunk_DWIM(d, + (struct chunk *)strtol(cmds[1],0,0), + strtol(cmds[2],0,0), + strtol(cmds[3],0,0), + strtol(cmds[4],0,0), + strtol(cmds[5],0,0))); + continue; + } + if (!strcasecmp(*cmds,"mknod")) { + MakeDevDisk(d,"/tmp"); + continue; + } + if (!strcasecmp(*cmds,"delete") && ncmd == 2) { + printf("delete = %d\n", + Delete_Chunk(d, + (struct chunk *)strtol(cmds[1],0,0))); + continue; + } + if (!strcasecmp(*cmds,"allfreebsd")) { + All_FreeBSD(d, 0); + continue; + } + if (!strcasecmp(*cmds,"dedicate")) { + All_FreeBSD(d, 1); + continue; + } + if (!strcasecmp(*cmds,"sanitize")) { + Sanitize_Bios_Geom(d); + continue; + } + if (!strcasecmp(*cmds,"bios") && ncmd == 4) { + Set_Bios_Geom(d, + strtol(cmds[1],0,0), + strtol(cmds[2],0,0), + strtol(cmds[3],0,0)); + continue; + } + if (!strcasecmp(*cmds,"list")) { + cp = Disk_Names(); + printf("Disks:"); + for(i=0;cp[i];i++) { + printf(" %s",cp[i]); + free(cp[i]); + } + free(cp); + continue; + } + if (!strcasecmp(*cmds,"create") && ncmd == 6) { + + printf("Create=%d\n", + Create_Chunk(d, + strtol(cmds[1],0,0), + strtol(cmds[2],0,0), + strtol(cmds[3],0,0), + strtol(cmds[4],0,0), + strtol(cmds[5],0,0))); + continue; + } + if (!strcasecmp(*cmds,"read")) { + db = d; + if (ncmd > 1) + d = Open_Disk(cmds[1]); + else + d = Open_Disk(argv[1]); + if (d) + Free_Disk(db); + else + d = db; + continue; + } + if (!strcasecmp(*cmds,"scan")) { + Scan_Disk(d); + continue; + } + if (!strcasecmp(*cmds,"bteasy")) { + Set_Boot_Mgr(d,bteasy17); + continue; + } + if (!strcasecmp(*cmds,"mbr")) { + Set_Boot_Mgr(d,mbr); + continue; + } +#ifndef __alpha__ /* don't think this compiles on i386 either */ + if (!strcasecmp(*cmds,"boot")) { + Set_Boot_Blocks(d,boot1,boot2); + continue; + } +#endif + if (!strcasecmp(*cmds,"write")) { + printf("Write=%d\n", + Write_Disk(d)); + Free_Disk(d); + d = Open_Disk(d->name); + continue; + } + if (strcasecmp(*cmds,"help")) + printf("\007ERROR\n"); + printf("CMDS:\n"); + printf("\tallfreebsd\n"); + printf("\tdedicate\n"); + printf("\tbios cyl hd sect\n"); + printf("\tboot\n"); + printf("\tbteasy17\n"); +#if 0 + printf("\tcollapse [pointer]\n"); +#endif + printf("\tcreate offset size enum subtype flags\n"); + printf("\t\tsubtype(part): swap=1, ffs=7\n"); + printf("\tdelete pointer\n"); + printf("\tlist\n"); + printf("\tmbr\n"); +#if 0 + printf("\tphys cyl hd sect\n"); +#endif + printf("\tquit\n"); + printf("\tread [disk]\n"); + printf("\tscan\n"); + printf("\twrite\n"); + printf("\nENUM:\n\t"); + for(i=0;chunk_n[i];i++) + printf("%d = %s%s",i,chunk_n[i],i == 4 ? "\n\t" : " "); + printf("\n"); + + } + exit (0); +} diff --git a/lib/libdisk/write_disk.c b/lib/libdisk/write_disk.c new file mode 100644 index 0000000..60ddbda --- /dev/null +++ b/lib/libdisk/write_disk.c @@ -0,0 +1,284 @@ +/* + * ---------------------------------------------------------------------------- + * "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 BBSIZE 8192 +#define SBSIZE 8192 +#define DEF_RPM 3600 +#define DEF_INTERLEAVE 1 + +#define WHERE(offset,disk) (disk->flags & DISK_ON_TRACK ? offset + 63 : offset) +int +Write_FreeBSD(int fd, struct disk *new, struct disk *old, struct chunk *c1) +{ + struct disklabel *dl; + struct chunk *c2; + int i,j; + void *p; + u_char buf[BBSIZE]; +#ifdef __alpha__ + u_long *lp, sum; +#endif + + for(i=0;i<BBSIZE/512;i++) { + p = read_block(fd,WHERE(i + c1->offset,new)); + memcpy(buf+512*i,p,512); + free(p); + } +#if defined(__i386__) + if(new->boot1) + memcpy(buf,new->boot1,512); + + if(new->boot2) + memcpy(buf+512,new->boot2,BBSIZE-512); +#elif defined(__alpha__) + if(new->boot1) + memcpy(buf+512,new->boot1,BBSIZE-512); +#endif + + dl = (struct disklabel *) (buf+512*LABELSECTOR+LABELOFFSET); + memset(dl,0,sizeof *dl); + + for(c2=c1->part;c2;c2=c2->next) { + if (c2->type == unused) continue; + if (!strcmp(c2->name,"X")) continue; +#ifdef __alpha__ + j = c2->name[strlen(c2->name) - 1] - 'a'; +#else + j = c2->name[strlen(new->name) + 2] - 'a'; +#endif + if (j < 0 || j >= MAXPARTITIONS || j == RAW_PART) { +#ifdef DEBUG + warn("Weird parititon letter %c",c2->name[strlen(new->name) + 2]); +#endif + continue; + } + dl->d_partitions[j].p_size = c2->size; + dl->d_partitions[j].p_offset = c2->offset; + dl->d_partitions[j].p_fstype = c2->subtype; + } + + dl->d_bbsize = BBSIZE; + /* + * Add in defaults for superblock size, interleave, and rpms + */ + dl->d_sbsize = SBSIZE; + dl->d_interleave = DEF_INTERLEAVE; + dl->d_rpm = DEF_RPM; + + strcpy(dl->d_typename,c1->name); + + dl->d_secsize = 512; + dl->d_secperunit = new->chunks->size; + dl->d_ncylinders = new->bios_cyl; + dl->d_ntracks = new->bios_hd; + dl->d_nsectors = new->bios_sect; + dl->d_secpercyl = dl->d_ntracks * dl->d_nsectors; + + dl->d_npartitions = MAXPARTITIONS; + + dl->d_type = new->name[0] == 's' || new->name[0] == 'd' || + new->name[0] == 'o' ? DTYPE_SCSI : DTYPE_ESDI; + dl->d_partitions[RAW_PART].p_size = c1->size; + dl->d_partitions[RAW_PART].p_offset = c1->offset; + + if(new->flags & DISK_ON_TRACK) + for(i=0;i<MAXPARTITIONS;i++) + if (dl->d_partitions[i].p_size) + dl->d_partitions[i].p_offset += 63; + dl->d_magic = DISKMAGIC; + dl->d_magic2 = DISKMAGIC; + dl->d_checksum = dkcksum(dl); + +#ifdef __alpha__ + /* + * Tell SRM where the bootstrap is. + */ + lp = (u_long *)buf; + lp[60] = 15; + lp[61] = 1; + lp[62] = 0; + + /* + * Generate the bootblock checksum for the SRM console. + */ + for (lp = (u_long *)buf, i = 0, sum = 0; i < 63; i++) + sum += lp[i]; + lp[63] = sum; +#endif + + for(i=0;i<BBSIZE/512;i++) { + write_block(fd,WHERE(i + c1->offset,new),buf+512*i); + } + + return 0; +} + +int +Write_Extended(int fd, struct disk *new, struct disk *old, struct chunk *c1) +{ + return 0; +} + +static void +Write_Int32(u_int32_t *p, u_int32_t v) +{ + u_int8_t *bp = (u_int8_t *)p; + bp[0] = (v >> 0) & 0xff; + bp[1] = (v >> 8) & 0xff; + bp[2] = (v >> 16) & 0xff; + bp[3] = (v >> 24) & 0xff; +} + +int +Write_Disk(struct disk *d1) +{ + int fd,i,j; + struct disk *old = 0; + struct chunk *c1; + int ret = 0; + char device[64]; + u_char *mbr; + struct dos_partition *dp,work[NDOSPART]; + int s[4]; + int one = 1; + int zero = 0; + + strcpy(device,"/dev/r"); + strcat(device,d1->name); + + fd = open(device,O_RDWR); + if (fd < 0) { +#ifdef DEBUG + warn("open(%s) failed",device); +#endif + return 1; + } + ioctl(fd, DIOCWLABEL, &one); + + memset(s,0,sizeof s); + mbr = read_block(fd,WHERE(0,d1)); + dp = (struct dos_partition*) (mbr + DOSPARTOFF); + memcpy(work,dp,sizeof work); + dp = work; + free(mbr); + for (c1=d1->chunks->part; c1 ; c1 = c1->next) { + if (c1->type == unused) continue; + if (!strcmp(c1->name,"X")) continue; +#ifndef __alpha__ + j = c1->name[4] - '1'; + j = c1->name[strlen(d1->name) + 1] - '1'; + if (j < 0 || j > 3) + continue; + s[j]++; +#endif + if (c1->type == extended) + ret += Write_Extended(fd, d1,old,c1); + if (c1->type == freebsd) + ret += Write_FreeBSD(fd, d1,old,c1); + +#ifndef __alpha__ + Write_Int32(&dp[j].dp_start, c1->offset); + Write_Int32(&dp[j].dp_size, c1->size); + + i = c1->offset; + if (i >= 1024*d1->bios_sect*d1->bios_hd) { + dp[j].dp_ssect = 0xff; + dp[j].dp_shd = 0xff; + dp[j].dp_scyl = 0xff; + } else { + dp[j].dp_ssect = i % d1->bios_sect; + i -= dp[j].dp_ssect++; + i /= d1->bios_sect; + dp[j].dp_shd = i % d1->bios_hd; + i -= dp[j].dp_shd; + i /= d1->bios_hd; + dp[j].dp_scyl = i; + i -= dp[j].dp_scyl; + dp[j].dp_ssect |= i >> 2; + } + +#ifdef DEBUG + printf("S:%lu = (%x/%x/%x)", + c1->offset,dp[j].dp_scyl,dp[j].dp_shd,dp[j].dp_ssect); +#endif + + i = c1->end; + dp[j].dp_esect = i % d1->bios_sect; + i -= dp[j].dp_esect++; + i /= d1->bios_sect; + dp[j].dp_ehd = i % d1->bios_hd; + i -= dp[j].dp_ehd; + i /= d1->bios_hd; + if (i>1023) i = 1023; + dp[j].dp_ecyl = i; + i -= dp[j].dp_ecyl; + dp[j].dp_esect |= i >> 2; + +#ifdef DEBUG + printf(" E:%lu = (%x/%x/%x)\n", + c1->end,dp[j].dp_ecyl,dp[j].dp_ehd,dp[j].dp_esect); +#endif + + dp[j].dp_typ = c1->subtype; + if (c1->flags & CHUNK_ACTIVE) + dp[j].dp_flag = 0x80; + else + dp[j].dp_flag = 0; +#endif + } +#ifndef __alpha__ + j = 0; + for(i=0;i<NDOSPART;i++) { + if (!s[i]) + memset(dp+i,0,sizeof *dp); + if (dp[i].dp_flag) + j++; + } + if (!j) + for(i=0;i<NDOSPART;i++) + if (dp[i].dp_typ == 0xa5) + dp[i].dp_flag = 0x80; + + mbr = read_block(fd,WHERE(0,d1)); + if (d1->bootmgr) + memcpy(mbr,d1->bootmgr,DOSPARTOFF); + memcpy(mbr+DOSPARTOFF,dp,sizeof *dp * NDOSPART); + mbr[512-2] = 0x55; + mbr[512-1] = 0xaa; + write_block(fd,WHERE(0,d1),mbr); +#endif + + i = 1; + i = ioctl(fd,DIOCSYNCSLICEINFO,&i); +#ifdef DEBUG + if (i != 0) + warn("ioctl(DIOCSYNCSLICEINFO)"); +#endif + ioctl(fd, DIOCWLABEL, &zero); + close(fd); + return 0; +} + |