diff options
Diffstat (limited to 'package/aboot/src/tools/e2writeboot.c')
-rw-r--r-- | package/aboot/src/tools/e2writeboot.c | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/package/aboot/src/tools/e2writeboot.c b/package/aboot/src/tools/e2writeboot.c new file mode 100644 index 000000000..58cbec1b7 --- /dev/null +++ b/package/aboot/src/tools/e2writeboot.c @@ -0,0 +1,254 @@ +/* Program to write a primary bootstrap file to a LINUX ext2 + * file system. + * + * Usage: e2writeboot fs-image bootfile + * + * It is assumed that the "bootfile" is a COFF executable with text, + * data, and bss contiguous. + */ + +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include <sys/stat.h> + +#include <e2lib.h> + +#if defined(__linux__) +# include <sys/types.h> +#elif defined(__alpha__) && defined(__osf1__) + typedef unsigned long u_int64_t; +#elif defined(__GNUC__) + typedef unsigned long long u_int64_t; +#endif + +struct boot_block { + u_int64_t vax_code[17]; + u_int64_t reserved[43]; + u_int64_t count; + u_int64_t lbn; + u_int64_t flags; + u_int64_t chk_sum; +}; + +#define CONSOLE_BLOCK_SIZE 512 + +extern int big_endian; +extern unsigned short swap16(); +extern unsigned int swap32(); + + +int +main(int argc, char ** argv) +{ + char fsname[512]; + char iobuf[1024]; + char namebuf[EXT2_NAME_LEN+1]; + struct ext2_inode * ip; + int filesize; + int infile; + int blkno; + int bootstrap_size; + int i; + int bs_start; + char *bsbuf; + int blocksize; + struct boot_block *bbp; + u_int64_t *lbp, checksum; + struct stat st; + + if (argc != 3) { + printf("Usage: %s ext2-fs input-file\n", argv[0]); + exit(1); + } + + strcpy(fsname, argv[1]); + strcpy(namebuf, "/linuxboot"); + + + /* "Open" the file system */ + if (ext2_init(fsname, O_RDWR) < 0) { + exit(1); + } + + /* Open the input file */ + infile = open(argv[2], 0); + if (infile < 0) { + perror(argv[2]); + ext2_close(); + exit(1); + } + + /* Figure out just how much data the input file is going + * to require us to put out. (text+data+bss). + */ + if (fstat(infile, &st) == -1) { + perror("fstat"); + ext2_close(); + exit(1); + } + blocksize = ext2_blocksize(); + bootstrap_size = st.st_size; + printf("bootstrap_size: %d -> ", bootstrap_size); + bootstrap_size += blocksize-1; + bootstrap_size &= ~(blocksize-1); + printf("%d\n", bootstrap_size); + + /* Allocate a buffer to hold the entire bootstrap, then read + * in the text+data segments. + */ + bsbuf = (char *)malloc(bootstrap_size); + memset(bsbuf, 0, bootstrap_size); + read(infile, bsbuf, bootstrap_size); + close(infile); + + /* Get the inode for the file we want to create */ + ip = ext2_namei(namebuf); + if(ip) { + /* This file exists. Make sure it's a regular file, then + * truncate it. + */ + if(!S_ISREG(ip->i_mode)) { + printf("%s: Not a regular file. Must remove it first.\n", namebuf); + ext2_iput(ip); + ext2_close(); + exit(1); + } + + printf("Using existing file %s\n", namebuf); + ext2_truncate(ip); + } + else { + /* Doesn't exist. Must get the parent directory's inode. */ + char dirname[EXT2_NAME_LEN+1]; + char filename[EXT2_NAME_LEN+1]; + struct ext2_inode *dip; + int inumber; + char *cp; + int i; + + strcpy(dirname, namebuf); + cp = strrchr(dirname, '/'); + if(cp) { + *cp = '\0'; + strcpy(filename, cp+1); + } + else { + strcpy(filename, dirname); + strcpy(dirname, "/"); + } + + dip = ext2_namei(dirname); + if(!dip) { + printf("Directory %s does not exist\n", dirname); + ext2_close(); + exit(1); + } + + printf("Creating new file %s in directory %s\n", filename, dirname); + + /* Get an inode for the file */ + inumber = ext2_ialloc(); + ip = ext2_iget(inumber); + + if(!ip) { + printf("PANIC! ip == NULL\n"); + exit(1); + } + + /* Create the directory entry */ + ext2_mknod(dip, filename, inumber); + + /* We're done with the directory for now... */ + ext2_iput(dip); + + /* Set certain fields in the inode (we're not going to get + * fancy here... just choose a safe set of defaults...) + */ + ip->i_mode = 0550 | S_IFREG; /* Regular file, r-xr-x--- */ + ip->i_uid = 0; /* Owned by root */ + ip->i_gid = 0; /* Group is system */ + ip->i_size = 0; + ip->i_atime = ip->i_ctime = ip->i_mtime = time(0); + ip->i_dtime = 0; + ip->i_links_count = 1; + ip->i_blocks = 0; + ip->i_flags = 0; /* Nothing special */ + for(i = 0; i < EXT2_N_BLOCKS; i++) { + ip->i_block[i] = 0; + } + ip->i_version = 0; + ip->i_file_acl = 0; + ip->i_frag = 0; + ip->i_fsize = 0; + ip->i_reserved1 = ip->i_pad1 = ip->i_reserved2[0] = 0; + + } + + /* At this point we have an inode for an empty regular file. + * Fill it up! + */ + + bs_start = ext2_fill_contiguous(ip, bootstrap_size/blocksize); + if(bs_start <= 0) { + printf("Cannot allocate blocks for %s... goodbye!\n", argv[2]); + ext2_close(); + exit(1); + } + + /* Write what we've got out to the file */ + filesize = bootstrap_size; + blkno = 0; + while(filesize > 0) { + ext2_bwrite(ip, blkno, bsbuf+(blkno*blocksize)); + blkno++; + filesize -= blocksize; + } + + ip->i_size = bootstrap_size; + ip->i_mtime = time(0); + + + /* Prepare and write out a bootblock */ + memset(iobuf, 0, blocksize); + bbp = (struct boot_block *)iobuf; + + bbp->count = bootstrap_size / CONSOLE_BLOCK_SIZE; + bbp->lbn = (bs_start * blocksize) / CONSOLE_BLOCK_SIZE; + bbp->flags = 0; + + /* Compute the checksum */ + checksum = 0; + lbp = (u_int64_t*) bbp; + for (i = 0; i < CONSOLE_BLOCK_SIZE/8; ++i) { + checksum += lbp[i]; + } + bbp->chk_sum = checksum; + + if(big_endian) { + /* Need to flip the bootblock fields so they come out + * right on disk... + */ + bbp->count = (((u_int64_t) swap32(bbp->count & 0xffffffff) << 32) + | swap32(bbp->count >> 32)); + bbp->lbn = (((u_int64_t) swap32(bbp->lbn & 0xffffffff) << 32) + | swap32(bbp->lbn >> 32)); + bbp->flags = (((u_int64_t) swap32(bbp->flags & 0xffffffff) << 32) + | swap32(bbp->flags >> 32)); + bbp->chk_sum = (((u_int64_t) swap32(bbp->chk_sum & 0xffffffff) << 32) + | swap32(bbp->chk_sum >> 32)); + } + + ext2_write_bootblock((char *) bbp); + + ext2_iput(ip); + ext2_close(); + + printf("%d bytes written to %s\n", bootstrap_size, namebuf); + return 0; +} |