diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2017-12-31 18:47:16 +0100 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2017-12-31 18:47:25 +0100 |
commit | 3a96085b999220c4da0c5ef7d1f7ba26b9ddfb98 (patch) | |
tree | 77f1445aae2e6be5135594e95986b3278bbc061c /package/aboot/src/sdisklabel/swriteboot.c | |
parent | cc28479164b8dc8afd4310716da32f16022f5974 (diff) |
dec-multia: make netboot possible, add aboot bootloader
Diffstat (limited to 'package/aboot/src/sdisklabel/swriteboot.c')
-rw-r--r-- | package/aboot/src/sdisklabel/swriteboot.c | 226 |
1 files changed, 226 insertions, 0 deletions
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; +} |