diff options
Diffstat (limited to 'package/aboot/src/sdisklabel')
-rw-r--r-- | package/aboot/src/sdisklabel/.cvsignore | 2 | ||||
-rw-r--r-- | package/aboot/src/sdisklabel/Makefile | 15 | ||||
-rw-r--r-- | package/aboot/src/sdisklabel/README | 105 | ||||
-rw-r--r-- | package/aboot/src/sdisklabel/library.c | 79 | ||||
-rw-r--r-- | package/aboot/src/sdisklabel/library.h | 8 | ||||
-rw-r--r-- | package/aboot/src/sdisklabel/sdisklabel.c | 241 | ||||
-rw-r--r-- | package/aboot/src/sdisklabel/swriteboot.c | 226 |
7 files changed, 676 insertions, 0 deletions
diff --git a/package/aboot/src/sdisklabel/.cvsignore b/package/aboot/src/sdisklabel/.cvsignore new file mode 100644 index 000000000..2ffbe5c05 --- /dev/null +++ b/package/aboot/src/sdisklabel/.cvsignore @@ -0,0 +1,2 @@ +sdisklabel +swriteboot diff --git a/package/aboot/src/sdisklabel/Makefile b/package/aboot/src/sdisklabel/Makefile new file mode 100644 index 000000000..045fd3920 --- /dev/null +++ b/package/aboot/src/sdisklabel/Makefile @@ -0,0 +1,15 @@ +ifndef ($(CC)) +CC ?= gcc +endif +override CFLAGS += -g -O2 -I../include -Wall $(CPPFLAGS) + +all: sdisklabel swriteboot + +sdisklabel: sdisklabel.o library.o + $(CC) $(LDFLAGS) $(CFLAGS) sdisklabel.o library.o -o sdisklabel + +swriteboot: swriteboot.o library.o + $(CC) $(LDFLAGS) $(CFLAGS) swriteboot.o library.o -o swriteboot + +clean: + rm -f sdisklabel swriteboot *.o diff --git a/package/aboot/src/sdisklabel/README b/package/aboot/src/sdisklabel/README new file mode 100644 index 000000000..45b4636d0 --- /dev/null +++ b/package/aboot/src/sdisklabel/README @@ -0,0 +1,105 @@ +These are sources and binaries for a Linux/Alpha boot file installer +and disk partitioner. They're horrible, and should be destroyed. +We're going to assume you don't have OSF/1, but want to use your hard +drive. If you have OSF/1, what are you doing in here??!?!?!!? + +The program also assumes you have a SCSI disk with 512-byte sectors, +tho it should work fine on an IDE drive as well. All sizes are +specified on the command line in sectors. + +There are 8 partitions in total, and are numbered from 0 to 7. +Partitions have to be added sequentially, as this program won't let +you leave empty partitions unlike many BSD disklabel programs. + +First off, if you have an invalid disk label (you've never run this +program before) you get to do + + sdisklabel /dev/sda zero + +(/dev/sda is the device you're partitioning, substitute as +appropriate). + +This zeros out your disk label. Only do this if you really want to +zero your disk label. It just does it; it doesn't ask, or warn, or +anything. + +The program also probably printed out the size of your disk in K. If +it was wrong, you now get to use the "size xxx" option along with the +rest of these commands. The size isn't critical, it's just used to try +and make sure you don't go past the end of the disk. + +Next, add your first partition. This *doesn't* start from 0, as you +have to leave room for the boot loader and other stuff. 256K (or 512 +sectors) will be enough. + +Let's pretend that you want to make a 250000K partition starting +from sector offset 512: + + sdisklabel /dev/sda 0 512 500000 8 print + +The last number is the filesystem type, and is currently 8 for ext2fs +filesystems. (A different number would be used to specify an OSF/1 +partition, for example). + +If all was successful, the program should print out the partition (the +last keyword, "print", specifies that it should print the partition +after modifying it with the previous command), and you should see +something like +---------------------------------------------------------------- +I think your disk is 528870K total size. +If I'm wrong, override the size with the 'size num' option + +partition 0: type 8, starts sector 512, size 500000 +---------------------------------------------------------------- + +We can then add the next partition, which would be partition 1. +To add a second partition that is 200000K long, we'd run + sdisklabel /dev/sda 1 512256 400000 8 print +And both partitions would then be printed out. + +If for some reason the size got determined incorrectly, we'd do +instead + + sdisklabel /dev/sda size 528870 0 512 400000 8 print + +The size option should come immediately after the device name, and the +size is the total # of sectors on the drive. + +That wasn't too bad, was it? The program doesn't do enough error +checking, but it should work OK if you don't try to abuse it. + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +Adding a bootstrap to the HD + +This isn't exactly trivial, and should be done immediately after +setting up the partitions (but not before...). I can't be held +responsible if the bootstrap writer wipes your drive-it does hardly +any error checking, tho it tries to make sure that you're not going to +wipe out any partitions before it starts writing. + +The program basically writes a raw binary image (*not* an a.out format file) +to the disk starting from sector 2. This can be generated from an executable +by using the arch/alpha/linux/tools/build program found in the kernel +distribution, or the similar program in the aboot distributiion. So to +install the bootloader in bootlx, assuming you've partitioned your disk (and +left enough blank space between the start of the disk and the first +partition to hold the bootloader): + + swriteboot /dev/sda bootlx + +When using aboot, you can also append a kernel image by using + + swriteboot /dev/sda bootlx vmlinux.gz + +If you invoke swriteboot with the '-v' option, it will be a bit more +verbose. + +If you have to partition your disk with a program that does not allow to +leave a blank (unpartitiones) space at the beginning for the bootloader, +create a partition of the desired size instead. swriteboot will complain +that the desired boot area overlaps with that partition, so you must use + + swriteboot -f# ... + +where # is the partition number to force overwriting this area. diff --git a/package/aboot/src/sdisklabel/library.c b/package/aboot/src/sdisklabel/library.c new file mode 100644 index 000000000..7c9b198fd --- /dev/null +++ b/package/aboot/src/sdisklabel/library.c @@ -0,0 +1,79 @@ +#include <stdio.h> +#include <sys/types.h> +#include <string.h> +#include <unistd.h> +#include <disklabel.h> +#include "library.h" + +int read_disklabel(int fd,struct disklabel *d) { + if(lseek(fd,LABELOFFSET,SEEK_SET)<0) { + return -1; + } + if(read(fd,d,sizeof(*d))!=sizeof(*d)) { + return -1; + } + if(d->d_magic!=DISKLABELMAGIC || d->d_magic2!=DISKLABELMAGIC) { + fprintf(stderr,"Existing disk label is corrupt\n"); + return -1; + } + return 0; +} + +int dosumlabel(int fd,struct disklabel *d) { + u_int64_t buf[128]; + int x; + u_int64_t sum=0; + + if(lseek(fd,0,SEEK_SET)<0) { + return -1; + } + if(read(fd,buf,64*sizeof(u_int64_t))!=(64*sizeof(u_int64_t))) { + return -1; + } + memcpy(&buf[LABELOFFSET/sizeof(u_int64_t)],d,sizeof(*d)); + for(x=0;x<63;x++) { + sum+=buf[x]; + } + if(lseek(fd,63*sizeof(u_int64_t),SEEK_SET)<0) { + return -1; + } + if(write(fd,&sum,sizeof(sum))!=sizeof(sum)) { + return -1; + } + return 0; +} + +static int does_overlap(int a1,int a2,int b1,int b2) { + if(a1>b1 && a1<b2) { + return 1; + } + if(a2>b1 && a2<b2) { + return 1; + } + if(b1>a1 && b1<a2) { + return 1; + } + if(b2>a1 && b2<a2) { + return 1; + } + return 0; +} + +/* + returns the number of the partition overlapping with the area + from offset to endplace, while ignoring partitions in the bitset ignore. +*/ +int overlaplabel(struct disklabel *d,int offset,int endplace,unsigned force) { + int x; + + for(x=0;x<d->d_npartitions;x++) { + if((force & (1U << x)) == 0) { + int part_offset=d->d_partitions[x].p_offset; + int part_end=d->d_partitions[x].p_offset+d->d_partitions[x].p_size; + if(part_end>0 && does_overlap(part_offset,part_end,offset,endplace)) + return x; + } + } + return -1; +} + diff --git a/package/aboot/src/sdisklabel/library.h b/package/aboot/src/sdisklabel/library.h new file mode 100644 index 000000000..cdb023df2 --- /dev/null +++ b/package/aboot/src/sdisklabel/library.h @@ -0,0 +1,8 @@ +#ifndef _LIBRARY_H +#define _LIBRARY_H + +int read_disklabel(int fd,struct disklabel *d); +int dosumlabel(int fd,struct disklabel *d); +int overlaplabel(struct disklabel *d,int offset,int endplace, unsigned force); + +#endif diff --git a/package/aboot/src/sdisklabel/sdisklabel.c b/package/aboot/src/sdisklabel/sdisklabel.c new file mode 100644 index 000000000..bc7b42a74 --- /dev/null +++ b/package/aboot/src/sdisklabel/sdisklabel.c @@ -0,0 +1,241 @@ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <ctype.h> +#include <string.h> +#include <unistd.h> +#include <disklabel.h> +#include <sys/ioctl.h> +#include <linux/hdreg.h> +#include "library.h" + +/* from linux/fs.h */ +#define BLKSSZGET _IO(0x12,104) /* get block device sector size */ +#define BLKGETSIZE _IO(0x12,96) /* return device size */ + +int label_modified=0; +int force=0; + +int +write_disklabel (int fd,struct disklabel *d) +{ + dosumlabel(fd,d); + if(lseek(fd,LABELOFFSET,SEEK_SET)<0) { + return -1; + } + if(write(fd,d,sizeof(*d))!=sizeof(*d)) { + return -1; + } + return 0; +} + +void +fixmagic (int fd,struct disklabel *d) +{ + d->d_magic=DISKLABELMAGIC; + d->d_magic2=DISKLABELMAGIC; + d->d_type=DTYPE_SCSI; + d->d_secsize=512; + strcpy(d->d_typename,"SCSI"); +} + +void +zero_disklabel (int fd,struct disklabel *d) +{ + memset(d,0,sizeof(*d)); + fixmagic(fd,d); + label_modified=1; +} + +void +print_disklabel(int fd,struct disklabel *d) +{ + int x; + for(x=0;x<d->d_npartitions;x++) { + printf("partition %d: type %d, starts sector %d, size %d\n", + x, d->d_partitions[x].p_fstype, + d->d_partitions[x].p_offset, d->d_partitions[x].p_size); + } +} + +int total_disk_size, heads, sectors, cylinders; +/* FIXME: use BLKSSZGET to get sector size. (depends on linux >=2.4) */ +int sector_size=512; + +#ifdef __linux__ + +void +set_disk_size (int fd) +{ + struct hd_geometry hd; + unsigned long blocks; + unsigned int sectors_per_block; + int r1, r2; + + sectors_per_block = sector_size / 512; + heads = sectors = cylinders = blocks = 0; + + r1 = ioctl(fd,HDIO_GETGEO,&hd); + + if (r1) { + perror("ioctl HDIO_GETGEO"); + } else { + heads = hd.heads; + sectors = hd.sectors; + cylinders = hd.cylinders; + if (heads * sectors * cylinders == 0) { r1 = -1; } + /* fdisk says: "never use hd.cylinders - it is truncated" + if BLKGETSIZE works we'll calculate our own value for + cylinders in a little bit, but for now, use it anyway */ + total_disk_size=(heads*sectors*cylinders); /* in sectors */ + } + + r2 = ioctl(fd,BLKGETSIZE, &blocks); + + if (r2) { + perror("ioctl BLKGETSIZE"); + } + + if (r1 && r2) { + if (!total_disk_size) { + fprintf(stderr, "Unable to get disk size. Please specify it with the size [size_in_sectors] option.\n\n"); + } + return; + } + + if (r1 == 0 && r2 == 0) { + total_disk_size = blocks; /* sizes in sectors */ + cylinders = blocks / (heads * sectors); + cylinders /= sectors_per_block; + } else if (r1 == 0) { + fprintf(stderr, "Unable to get disk geometry. Guessing number of sectors from disk size.\n"); + cylinders = heads = 1; + sectors = blocks / sectors_per_block; + } + fprintf(stderr,"%d heads, %d sectors, %d cylinders %dK total size\n", + heads, sectors, cylinders, total_disk_size/2); +} +#endif + +int +set_partition (int fd,struct disklabel *d,int num,int offset,int size,int fstype) +{ + int endplace=offset+size; + int x; + + if(endplace>total_disk_size) { + fprintf(stderr,"endplace is %d total_disk_size is %d\n",endplace,total_disk_size); + if (!force) return -1; + /* correct the discrepancy */ + size = total_disk_size-offset; + endplace=total_disk_size; + fprintf(stderr,"Warning: changing endplace to %d and size to %d\n",endplace,size); + } + + if(num>d->d_npartitions) { + fprintf(stderr,"Partition not consecutive! This would leave empty partitions.\nNext unset partition is %d.\n",d->d_npartitions); + if (!force) return -1; + } + x=overlaplabel(d,offset,endplace,1U<<num); + if(x!=-1) + fprintf(stderr,"Warning: added partition %d overlaps with partition %d\n",num,x); + + d->d_partitions[num].p_offset=offset; + d->d_partitions[num].p_size=size; + d->d_partitions[num].p_fstype=fstype; + if(num==d->d_npartitions) { + d->d_npartitions++; + } + label_modified=1; + return 0; +} + +void +usage (char *cmd_name) +{ + fprintf(stderr,"Usage: %s drive print\n",cmd_name); + fprintf(stderr," %s drive zero\n",cmd_name); + fprintf(stderr," %s drive partition_number offset_in_sectors size_in_sectors partition_type\n",cmd_name); + fprintf(stderr," %s drive sum\n",cmd_name); + fprintf(stderr," %s drive size size_in_sectors [other command]\n\n",cmd_name); + fprintf(stderr,"The print command may be placed before or after any other command.\n"); + fprintf(stderr,"The size command is used to override the size of the disk, if the\nprogram isn't able to obtain this information for some reason.\n"); + fprintf(stderr,"The partition type should be 8, unless you are creating\nlabels for OSF/1 partitions.\n"); +} + + +int +main (int argc,char **argv) +{ + struct disklabel d; + int fd,x; + + if(argc < 3) { + usage(argv[0]); + exit(1); + } + fd=open(argv[1],O_RDWR); + if(fd<0) { + perror("couldn't open scsi disk"); + exit(1); + } +#ifdef __linux__ + set_disk_size(fd); +#endif + if(strcmp(argv[2],"zero")==0) { + zero_disklabel(fd,&d); + } else { + if(read_disklabel(fd,&d)) { + fprintf(stderr,"Error reading disklabel\n"); + exit(1); + } + } + for(x=2;x<argc;) { + if(strcmp(argv[x],"size")==0 && ((x+1)<argc)) { + total_disk_size=atoi(argv[x+1]); + x+=2; + } + if(strcmp(argv[x],"sum")==0) { + dosumlabel(fd,&d); + x++; + } + else if(strcmp(argv[x],"zero")==0) { + zero_disklabel(fd,&d); + x++; + } + else if(strcmp(argv[x],"print")==0) { + print_disklabel(fd,&d); + x++; + } + else if(strcmp(argv[x],"force")==0) { + force=1; + x++; + } + else { + if((argc-x)>3 && isdigit(argv[x][0]) && isdigit(argv[x+1][0]) && isdigit(argv[x+2][0]) && isdigit(argv[x+3][0])) { + int partnum=atoi(argv[x]); + int offset=atoi(argv[x+1]); + int size=atoi(argv[x+2]); + int fstype=atoi(argv[x+3]); + if(partnum<0 || partnum>7) { + fprintf(stderr,"Partition number %d out of range--partitions should be between 0 and 7\n",partnum); + exit(1); + } + if(set_partition(fd,&d,partnum,offset,size,fstype)) { + fprintf(stderr,"Set of partition failed\n"); + exit(1); + } + x+=4; + } else { + fprintf(stderr,"Unrecognized option %s\n",argv[x]); + usage(argv[0]); + exit(1); + } + } + } + if(label_modified && write_disklabel(fd,&d)) { + fprintf(stderr,"Error writing disklabel\n"); + exit(1); + } + return 0; +} diff --git a/package/aboot/src/sdisklabel/swriteboot.c b/package/aboot/src/sdisklabel/swriteboot.c new file mode 100644 index 000000000..8c93d4402 --- /dev/null +++ b/package/aboot/src/sdisklabel/swriteboot.c @@ -0,0 +1,226 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#include "system.h" +#include <disklabel.h> +#include <config.h> +#include "library.h" + +#define SECT_SIZE 512 +#define BOOT_SECTOR 2 + +int read_configured_partition(int disk_fd, char* buf) +{ + u_int64_t bootsize, bootsect, bootpart = 0; + long *p = (long *) buf; + + if(lseek(disk_fd,60*8,SEEK_SET)<0) { + perror("lseek on disk"); + exit(1); + } + /* Find old configuration */ + read(disk_fd, &bootsize, sizeof(bootsize)); + read(disk_fd, &bootsect, sizeof(bootsect)); + if(lseek(disk_fd,SECT_SIZE*bootsect,SEEK_SET)<0) + return 0; /* probably random garbage in the boot block - not + a fatal error */ + read(disk_fd, buf, SECT_SIZE); + while ((char *)p < buf + SECT_SIZE) + if (*p++ == ABOOT_MAGIC) + bootpart = *p; + return bootpart; +} + +int main(int argc, char **argv) +{ + u_int64_t bootsize,kernelsize=0; + u_int64_t bootsect=BOOT_SECTOR; + u_int64_t magicnum=0; + int disk_fd,file_fd,kernel_fd=0; + struct disklabel dlabel; + struct stat s; + int x; + char buf[2048]; + int c; + int err=0, part, bootpart=0; + unsigned force_overlap=0; + int verbose=0; + extern int optind; + extern char *optarg; + char *bootfile=0, *device=0, *kernel=0; + + while ((c=getopt(argc,argv,"f:c:v?"))!=EOF) + switch(c) + { + case '?': + err=1; + break; + case 'f': + part = atoi(optarg); + if (part < 1 || part > 8) { + fprintf(stderr, "%s: partition number must be in range 1-8\n", + argv[0]); + exit(1); + } + force_overlap |= 1U << (part - 1); + break; + case 'c': + bootpart = atoi(optarg); + if (bootpart < 1 || bootpart > 8) { + fprintf(stderr, "%s: partition number must be in range 1-8\n", + argv[0]); + exit(1); + } + break; + case 'v': + verbose=1; + break; + default: + err=1; + break; + } + + if(optind<argc) + device=argv[optind++]; + if(optind<argc) + bootfile=argv[optind++]; + if(optind<argc) + kernel=argv[optind++]; + + if(!bootfile || !device || err) + { + fprintf(stderr, "Usage: %s [-f[1-8]] [-c[1-8]] [-v] disk bootfile [kernel]\n", + argv[0]); + exit(1); + } + + disk_fd=open(device,O_RDWR); + file_fd=open(bootfile,O_RDONLY); + if(disk_fd<0) { + perror("open disk device"); + exit(1); + } + if(file_fd<0) { + perror("open bootfile"); + exit(1); + } + + if(kernel) + { + kernel_fd=open(kernel,O_RDONLY); + if (kernel_fd<0) + { + perror("open kernel"); + exit(1); + } + else + { + if(fstat(kernel_fd,&s)) { + perror("fstat kernel"); + exit(1); + } + kernelsize=(s.st_size+SECT_SIZE-1)/SECT_SIZE; + } + } + if(read_disklabel(disk_fd,&dlabel)) { + fprintf(stderr,"Couldn't get a valid disk label, exiting\n"); + exit(1); + } + if(fstat(file_fd,&s)) { + perror("fstat bootfile"); + exit(1); + } + bootsize=(s.st_size+SECT_SIZE-1)/SECT_SIZE; + + if(-1 !=(x=overlaplabel(&dlabel,bootsect,bootsize+bootsect+kernelsize,force_overlap))) + { + fprintf(stderr, + "error: bootcode overlaps with partition #%d. " + "If you really want this, use -f%d\n", + x + 1, x + 1); + exit(1); + } + + if(!bootpart) { + bootpart = read_configured_partition(disk_fd, buf); + if (verbose) { + if (bootpart) { + printf("preserving boot partition %d\n", bootpart); + } else { + printf("could not find existing aboot, configuring for second partition\n"); + } + } + } else { + if (verbose) { + printf("setting boot partition to %d\n", bootpart); + } + } + if(lseek(disk_fd,60*8,SEEK_SET)<0) { + perror("lseek on disk"); + exit(1); + } + write(disk_fd,&bootsize,sizeof(bootsize)); + write(disk_fd,&bootsect,sizeof(bootsect)); + write(disk_fd,&magicnum,sizeof(magicnum)); + if (verbose) + { + fprintf(stderr,"bootsize:%lu sectors\n",bootsize); + fprintf(stderr,"bootsect:%lu\n",bootsect); + } + if(lseek(disk_fd,SECT_SIZE*bootsect,SEEK_SET)<0) { + perror("lseek #3 on disk\n"); + exit(1); + } + while((x=read(file_fd,buf,2048))>0) { + write(disk_fd,buf,x); + } + close(file_fd); + if (kernel_fd > 0 && kernelsize>0) + { + unsigned long len = 0; + + if (verbose) + fprintf(stderr,"kernel:%lu sectors\n",kernelsize); +#if 0 + if(lseek(disk,BOOT_SIZE+BOOT_SECTOR*SECT_SIZE,SEEK_SET)<0) { + perror("lseek #4 on disk\n"); + exit(1); + } +#endif + while((x=read(kernel_fd,buf,2048))>0) + { + write(disk_fd,buf,x); + len += x; + } + close(kernel_fd); + if ((len+SECT_SIZE-1)/SECT_SIZE != kernelsize) + fprintf(stderr,"warning: kernel read %lu, should be %lu\n",(len+SECT_SIZE-1)/SECT_SIZE,kernelsize); + } + /* Now write the aboot partition config if we had one */ + if (bootpart) { + long *p = (long *) buf; + + if(lseek(disk_fd,SECT_SIZE*bootsect,SEEK_SET)<0) { + perror("lseek #5 on disk\n"); + exit(1); + } + read(disk_fd, buf, SECT_SIZE); + while ((char *)p < buf + SECT_SIZE) { + if (*p++ == ABOOT_MAGIC) { + *p = bootpart; + } + } + lseek(disk_fd,SECT_SIZE*bootsect,SEEK_SET); + write(disk_fd, buf, SECT_SIZE); + } + dosumlabel(disk_fd,&dlabel); + close(disk_fd); + if(verbose) + fprintf(stderr,"done!\n"); + return 0; +} |