summaryrefslogtreecommitdiff
path: root/package/aboot/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'package/aboot/src/tools')
-rw-r--r--package/aboot/src/tools/.cvsignore5
-rw-r--r--package/aboot/src/tools/Makefile22
-rw-r--r--package/aboot/src/tools/abootconf.c125
-rw-r--r--package/aboot/src/tools/bio.c178
-rw-r--r--package/aboot/src/tools/bio.h4
-rw-r--r--package/aboot/src/tools/e2lib.c1473
-rw-r--r--package/aboot/src/tools/e2lib.h332
-rw-r--r--package/aboot/src/tools/e2writeboot.c254
-rw-r--r--package/aboot/src/tools/elfencap.c61
-rw-r--r--package/aboot/src/tools/isomarkboot.c239
-rw-r--r--package/aboot/src/tools/objstrip.c260
11 files changed, 2953 insertions, 0 deletions
diff --git a/package/aboot/src/tools/.cvsignore b/package/aboot/src/tools/.cvsignore
new file mode 100644
index 000000000..2197455e0
--- /dev/null
+++ b/package/aboot/src/tools/.cvsignore
@@ -0,0 +1,5 @@
+abootconf
+e2writeboot
+elfencap
+isomarkboot
+objstrip
diff --git a/package/aboot/src/tools/Makefile b/package/aboot/src/tools/Makefile
new file mode 100644
index 000000000..740b9cb9d
--- /dev/null
+++ b/package/aboot/src/tools/Makefile
@@ -0,0 +1,22 @@
+ifndef ($(CC))
+CC = gcc
+endif
+override CFLAGS = -g -O2 -Wall -I. -I../include $(CPPFLAGS)
+override LDFLAGS = -g
+override PGMS += e2writeboot abootconf elfencap objstrip
+
+EXEC_PREFIX = /usr
+
+all: $(PGMS)
+
+install: $(PGMS)
+ install -c -o root -g root -m 755 $(PGMS) $(EXEC_PREFIX)/bin
+
+clean:
+ rm -f *~ *.o *.a core $(PGMS)
+
+isomarkboot: isomarkboot.o ../lib/isolib.o
+e2writeboot: e2writeboot.o e2lib.o bio.o
+
+e2writeboot.o: e2lib.h
+e2lib.o: e2lib.h
diff --git a/package/aboot/src/tools/abootconf.c b/package/aboot/src/tools/abootconf.c
new file mode 100644
index 000000000..0d0ae075c
--- /dev/null
+++ b/package/aboot/src/tools/abootconf.c
@@ -0,0 +1,125 @@
+/*
+ * abootconf.c
+ *
+ * This file is part of aboot, the SRM bootloader for Linux/Alpha
+ * Copyright (C) 1996 Linus Torvalds, David Mosberger, and Michael Schwingen.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/fcntl.h>
+
+#include <config.h>
+
+
+const char * prog_name;
+
+int
+main (int argc, char ** argv)
+{
+ unsigned long sector[512 / sizeof(unsigned long)];
+ off_t aboot_pos;
+ size_t nbytes;
+ long part = -1;
+ int disk, i;
+
+ prog_name = argv[0];
+
+ if (argc != 2 && argc != 3) {
+ fprintf(stderr, "usage: %s device [partition]\n", prog_name);
+ exit(1);
+ }
+
+ if (argc > 2) {
+ errno = 0;
+ part = strtol(argv[2], 0, 10);
+ if (errno == ERANGE) {
+ fprintf(stderr, "%s: bad partition number %s\n",
+ prog_name, argv[2]);
+ exit(1);
+ }
+ }
+
+ disk = open(argv[1], part < 0 ? O_RDONLY : O_RDWR);
+ if (disk < 0) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ nbytes = read(disk, sector, sizeof(sector));
+ if (nbytes != sizeof(sector)) {
+ if ((long) nbytes < 0) {
+ perror("read");
+ } else {
+ fprintf(stderr, "%s: short read\n", prog_name);
+ }
+ exit(1);
+ }
+
+ aboot_pos = sector[61] * 512;
+
+ if (lseek(disk, aboot_pos, SEEK_SET) != aboot_pos) {
+ perror("lseek");
+ exit(1);
+ }
+
+ nbytes = read(disk, sector, sizeof(sector));
+ if (nbytes != sizeof(sector)) {
+ if ((long) nbytes < 0) {
+ perror("read");
+ } else {
+ fprintf(stderr, "%s: short read\n", prog_name);
+ }
+ exit(1);
+ }
+
+ for (i = 0; i < (int) (sizeof(sector)/sizeof(sector[0])); ++i) {
+ if (sector[i] == ABOOT_MAGIC)
+ break;
+ }
+ if (i >= (int) (sizeof(sector)/sizeof(sector[0]))) {
+ fprintf(stderr, "%s: could not find aboot on disk %s\n",
+ prog_name, argv[1]);
+ exit(1);
+ }
+
+ if (part < 0) {
+ printf("aboot.conf partition currently set to %ld\n",
+ sector[i + 1]);
+ exit(0);
+ }
+
+ if (lseek(disk, aboot_pos, SEEK_SET) != aboot_pos) {
+ perror("lseek");
+ exit(1);
+ }
+
+ sector[i + 1] = atoi(argv[2]);
+
+ nbytes = write(disk, sector, sizeof(sector));
+ if (nbytes != sizeof(sector)) {
+ if ((long) nbytes < 0) {
+ perror("write");
+ } else {
+ fprintf(stderr, "%s: short write\n", prog_name);
+ }
+ exit(1);
+ }
+ return 0;
+}
diff --git a/package/aboot/src/tools/bio.c b/package/aboot/src/tools/bio.c
new file mode 100644
index 000000000..c82161e62
--- /dev/null
+++ b/package/aboot/src/tools/bio.c
@@ -0,0 +1,178 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Buffered I/O functions. By cacheing the most recently used blocks,
+ * we can cut WAAY down on disk traffic...
+ */
+
+static int bio_fd = -1;
+static int bio_counter = 0;
+static int bio_blocksize = 0;
+
+struct bio_buf {
+ int blkno;
+ int last_access;
+ int dirty;
+ char * data;
+};
+
+#define NBUFS 32
+struct bio_buf buflist[NBUFS];
+
+/* initialize the buffer cache. Blow away anything that may
+ * have been previously cached...
+ */
+void
+binit(int fd, int blocksize)
+{
+ int i;
+
+ bio_fd = fd;
+ bio_blocksize = blocksize;
+
+ for(i = 0; i < NBUFS; i++) {
+ buflist[i].blkno = 0;
+ if(buflist[i].data) {
+ free(buflist[i].data);
+ }
+ buflist[i].data = 0;
+ buflist[i].last_access = 0;
+ buflist[i].dirty = 0;
+ }
+}
+
+/* Flush out any dirty blocks */
+void
+bflush(void)
+{
+ int i;
+
+ for(i = 0; i < NBUFS; i++) {
+ if(buflist[i].dirty) {
+#ifdef BIO_DEBUG
+ printf("bflush: writing block %d\n", buflist[i].blkno);
+#endif
+ lseek(bio_fd, buflist[i].blkno * bio_blocksize, 0);
+ write(bio_fd, buflist[i].data, bio_blocksize);
+ buflist[i].dirty = 0;
+ }
+ }
+}
+
+/* Read a block. */
+void
+bread(int blkno, void * blkbuf)
+{
+ int i;
+ int lowcount;
+ int lowcount_buf;
+
+ /* First, see if the block is already in memory... */
+ for(i = 0; i < NBUFS; i++) {
+ if(buflist[i].blkno == blkno) {
+ /* Got it! Bump the access count and return. */
+ buflist[i].last_access = ++bio_counter;
+#ifdef BIO_DEBUG
+ printf("bread: buffer hit on block %d\n", blkno);
+#endif
+ memcpy(blkbuf, buflist[i].data, bio_blocksize);
+ return;
+ }
+ }
+
+ /* Not in memory; need to find a buffer and read it in. */
+ lowcount = buflist[0].last_access;
+ lowcount_buf = 0;
+ for(i = 1; i < NBUFS; i++) {
+ if(buflist[i].last_access < lowcount) {
+ lowcount = buflist[i].last_access;
+ lowcount_buf = i;
+ }
+ }
+
+ /* If the buffer is dirty, we need to write it out... */
+ if(buflist[lowcount_buf].dirty) {
+#ifdef BIO_DEBUG
+ printf("bread: recycling dirty buffer %d for block %d\n",
+ lowcount_buf, buflist[lowcount_buf].blkno);
+#endif
+ lseek(bio_fd, buflist[lowcount_buf].blkno * bio_blocksize, 0);
+ write(bio_fd, buflist[lowcount_buf].data, bio_blocksize);
+ buflist[lowcount_buf].dirty = 0;
+ }
+
+#ifdef BIO_DEBUG
+ printf("bread: Using buffer %d for block %d\n", lowcount_buf, blkno);
+#endif
+
+ buflist[lowcount_buf].blkno = blkno;
+ if(!buflist[lowcount_buf].data) {
+ buflist[lowcount_buf].data = (char *)malloc(bio_blocksize);
+ }
+ lseek(bio_fd, blkno * bio_blocksize, 0);
+ if(read(bio_fd,buflist[lowcount_buf].data,bio_blocksize)!=bio_blocksize) {
+ perror("bread: I/O error");
+ }
+
+ buflist[lowcount_buf].last_access = ++bio_counter;
+ memcpy(blkbuf, buflist[lowcount_buf].data, bio_blocksize);
+}
+
+
+/* Write a block */
+void
+bwrite(int blkno, void * blkbuf)
+{
+ int i;
+ int lowcount;
+ int lowcount_buf;
+
+ /* First, see if the block is already in memory... */
+ for(i = 0; i < NBUFS; i++) {
+ if(buflist[i].blkno == blkno) {
+ /* Got it! Bump the access count and return. */
+#ifdef BIO_DEBUG
+ printf("bwrite: buffer hit on block %d\n", blkno);
+#endif
+ buflist[i].last_access = ++bio_counter;
+ memcpy(buflist[i].data, blkbuf, bio_blocksize);
+ buflist[i].dirty = 1;
+ return;
+ }
+ }
+
+ /* Not in memory; need to find a buffer and stuff it. */
+ lowcount = buflist[0].last_access;
+ lowcount_buf = 0;
+ for(i = 1; i < NBUFS; i++) {
+ if(buflist[i].last_access < lowcount) {
+ lowcount = buflist[i].last_access;
+ lowcount_buf = i;
+ }
+ }
+
+ /* If the buffer is dirty, we need to write it out... */
+ if(buflist[lowcount_buf].dirty) {
+#ifdef BIO_DEBUG
+ printf("bwrite: recycling dirty buffer %d for block %d\n",
+ lowcount_buf, buflist[lowcount_buf].blkno);
+#endif
+ lseek(bio_fd, buflist[lowcount_buf].blkno * bio_blocksize, 0);
+ write(bio_fd, buflist[lowcount_buf].data, bio_blocksize);
+ buflist[lowcount_buf].dirty = 0;
+ }
+
+#ifdef BIO_DEBUG
+ printf("bwrite: Using buffer %d for block %d\n", lowcount_buf, blkno);
+#endif
+
+ buflist[lowcount_buf].blkno = blkno;
+ if(!buflist[lowcount_buf].data) {
+ buflist[lowcount_buf].data = (char *)malloc(bio_blocksize);
+ }
+ buflist[lowcount_buf].last_access = ++bio_counter;
+ memcpy(buflist[lowcount_buf].data, blkbuf, bio_blocksize);
+ buflist[lowcount_buf].dirty = 1;
+}
diff --git a/package/aboot/src/tools/bio.h b/package/aboot/src/tools/bio.h
new file mode 100644
index 000000000..398590360
--- /dev/null
+++ b/package/aboot/src/tools/bio.h
@@ -0,0 +1,4 @@
+extern void binit (int fd, int blocksize);
+extern void bflush (void);
+extern void bread (int blkno, void * blkbuf);
+extern void bwrite (int blkno, void * blkbuf);
diff --git a/package/aboot/src/tools/e2lib.c b/package/aboot/src/tools/e2lib.c
new file mode 100644
index 000000000..56e4b66ef
--- /dev/null
+++ b/package/aboot/src/tools/e2lib.c
@@ -0,0 +1,1473 @@
+/* This is a library of functions that allow user-level programs to
+ * read and manipulate ext2 file systems. For convenience sake,
+ * this library maintains a lot of state information in static
+ * variables; therefore, it's not reentrant. We don't care for
+ * our applications 8-)
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <bio.h>
+#include <e2lib.h>
+
+
+#define MAX_OPEN_FILES 8
+
+int fd = -1;
+struct ext2_super_block sb;
+struct ext2_group_desc *gds;
+int ngroups = 0;
+int blocksize; /* Block size of this fs */
+int directlim; /* Maximum direct blkno */
+int ind1lim; /* Maximum single-indir blkno */
+int ind2lim; /* Maximum double-indir blkno */
+int ptrs_per_blk; /* ptrs/indirect block */
+char filename[256];
+int readonly; /* Is this FS read-only? */
+int verbose = 0;
+int big_endian = 0;
+
+static void ext2_ifree(int ino);
+static void ext2_free_indirect(int indirect_blkno, int level);
+
+
+struct inode_table_entry {
+ struct ext2_inode inode;
+ int inumber;
+ int free;
+ unsigned short old_mode;
+} inode_table[MAX_OPEN_FILES];
+
+/* Utility functions to byte-swap 16 and 32 bit quantities... */
+
+unsigned short
+swap16 (unsigned short s)
+{
+ return((unsigned short)( ((s << 8) & 0xff00) | ((s >> 8) & 0x00ff)));
+}
+
+unsigned int
+swap32 (unsigned int i)
+{
+ return((unsigned int)(
+ ((i << 24) & 0xff000000) |
+ ((i << 8) & 0x00ff0000) |
+ ((i >> 8) & 0x0000ff00) |
+ ((i >> 24) & 0x000000ff)) );
+}
+
+void
+ext2_swap_sb (struct ext2_super_block *sb)
+{
+ sb->s_inodes_count = swap32(sb->s_inodes_count);
+ sb->s_blocks_count = swap32(sb->s_blocks_count);
+ sb->s_r_blocks_count = swap32(sb->s_r_blocks_count);
+ sb->s_free_blocks_count = swap32(sb->s_free_blocks_count);
+ sb->s_free_inodes_count = swap32(sb->s_free_inodes_count);
+ sb->s_first_data_block = swap32(sb->s_first_data_block);
+ sb->s_log_block_size = swap32(sb->s_log_block_size);
+ sb->s_log_frag_size = swap32(sb->s_log_frag_size);
+ sb->s_blocks_per_group = swap32(sb->s_blocks_per_group);
+ sb->s_frags_per_group = swap32(sb->s_frags_per_group);
+ sb->s_inodes_per_group = swap32(sb->s_inodes_per_group);
+ sb->s_mtime = swap32(sb->s_mtime);
+ sb->s_wtime = swap32(sb->s_wtime);
+ sb->s_mnt_count = swap16(sb->s_mnt_count);
+ sb->s_max_mnt_count = swap16(sb->s_max_mnt_count);
+ sb->s_magic = swap16(sb->s_magic);
+ sb->s_state = swap16(sb->s_state);
+ sb->s_errors = swap16(sb->s_errors);
+ sb->s_pad = swap16(sb->s_pad);
+ sb->s_lastcheck = swap32(sb->s_lastcheck);
+ sb->s_checkinterval = swap32(sb->s_checkinterval);
+}
+
+void
+ext2_swap_gd (struct ext2_group_desc *gd)
+{
+ gd->bg_block_bitmap = swap32(gd->bg_block_bitmap);
+ gd->bg_inode_bitmap = swap32(gd->bg_inode_bitmap);
+ gd->bg_inode_table = swap32(gd->bg_inode_table);
+ gd->bg_free_blocks_count = swap16(gd->bg_free_blocks_count);
+ gd->bg_free_inodes_count = swap16(gd->bg_free_inodes_count);
+ gd->bg_used_dirs_count = swap16(gd->bg_used_dirs_count);
+ gd->bg_pad = swap16(gd->bg_pad);
+}
+
+void
+ext2_swap_inode (struct ext2_inode *ip)
+{
+ int i;
+
+ ip->i_mode = swap16(ip->i_mode);
+ ip->i_uid = swap16(ip->i_uid);
+ ip->i_size = swap32(ip->i_size);
+ ip->i_atime = swap32(ip->i_atime);
+ ip->i_ctime = swap32(ip->i_ctime);
+ ip->i_mtime = swap32(ip->i_mtime);
+ ip->i_dtime = swap32(ip->i_dtime);
+ ip->i_gid = swap16(ip->i_gid);
+ ip->i_links_count = swap16(ip->i_links_count);
+ ip->i_blocks = swap32(ip->i_blocks);
+ ip->i_flags = swap32(ip->i_flags);
+ ip->i_reserved1 = swap32(ip->i_reserved1);
+ for(i = 0; i < EXT2_N_BLOCKS; i++) {
+ ip->i_block[i] = swap32(ip->i_block[i]);
+ }
+ ip->i_version = swap32(ip->i_version);
+ ip->i_file_acl = swap32(ip->i_file_acl);
+ ip->i_dir_acl = swap32(ip->i_dir_acl);
+ ip->i_faddr = swap32(ip->i_faddr);
+ ip->i_pad1 = swap16(ip->i_pad1);
+}
+
+
+
+/* Initialize an ext2 filesystem; this is sort-of the same idea as
+ * "mounting" it. Read in the relevant control structures and
+ * make them available to the user. Returns 0 if successful, -1 on
+ * failure.
+ */
+int
+ext2_init (char * name, int access)
+{
+ int i;
+
+ /* Initialize the inode table */
+ for(i = 0; i < MAX_OPEN_FILES; i++) {
+ inode_table[i].free = 1;
+ inode_table[i].inumber = 0;
+ }
+
+ if((access != O_RDONLY) && (access != O_RDWR)) {
+ fprintf(stderr,
+ "ext2_init: Access must be O_RDONLY or O_RDWR, not %d\n",
+ access);
+ return(-1);
+ }
+
+ /* Open the device/file */
+ fd = open(name, access);
+ if(fd < 0) {
+ perror(filename);
+ return(-1);
+ }
+
+ if(access == O_RDONLY) {
+ readonly = 1;
+ }
+
+ /* Read in the first superblock */
+ lseek(fd, EXT2_MIN_BLOCK_SIZE, SEEK_SET);
+ if(read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
+ perror("ext2 sb read");
+ close(fd);
+ return(-1);
+ }
+
+ if((sb.s_magic != EXT2_SUPER_MAGIC) && (sb.s_magic != EXT2_SUPER_BIGMAGIC)) {
+ fprintf(stderr, "ext2 bad magic 0x%x\n", sb.s_magic);
+ close(fd);
+ return(-1);
+ }
+
+ if(sb.s_magic == EXT2_SUPER_BIGMAGIC) {
+ big_endian = 1;
+
+ /* Byte-swap the fields in the superblock... */
+ ext2_swap_sb(&sb);
+ }
+
+ if(sb.s_first_data_block != 1) {
+ fprintf(stderr,
+ "Brain-damaged utils can't deal with a filesystem\nwhere s_first_data_block != 1.\nRe-initialize the filesystem\n");
+ close(fd);
+ return(-1);
+ }
+
+ ngroups = (sb.s_blocks_count+sb.s_blocks_per_group-1)/sb.s_blocks_per_group;
+ gds = (struct ext2_group_desc *)
+ malloc((size_t)(ngroups * sizeof(struct ext2_group_desc)));
+
+ /* Read in the group descriptors (immediately follows superblock) */
+ if ((size_t) read(fd, gds, ngroups * sizeof(struct ext2_group_desc))
+ != (ngroups * sizeof(struct ext2_group_desc)))
+ {
+ perror("ext2_init: group desc read error");
+ return(-1);
+ }
+
+ if(big_endian) {
+ for(i = 0; i < ngroups; i++) {
+ ext2_swap_gd(&(gds[i]));
+ }
+ }
+
+ strcpy(filename, name);
+
+ /* Calculate direct/indirect block limits for this file system
+ * (blocksize dependent)
+ */
+ blocksize = EXT2_BLOCK_SIZE(&sb);
+ directlim = EXT2_NDIR_BLOCKS - 1;
+ ptrs_per_blk = blocksize/sizeof(unsigned int);
+ ind1lim = ptrs_per_blk + directlim;
+ ind2lim = (ptrs_per_blk * ptrs_per_blk) + directlim;
+
+ if(getenv("EXT2_VERBOSE")) {
+ verbose = 1;
+ }
+
+ binit(fd, blocksize);
+
+ if(verbose) {
+ printf("Initialized filesystem %s\n", filename);
+ printf(" %d blocks (%dKb), %d free (%dKb)\n",
+ sb.s_blocks_count, (sb.s_blocks_count * blocksize)/1024,
+ sb.s_free_blocks_count,
+ (sb.s_free_blocks_count * blocksize)/1024);
+ printf(" %d inodes, %d free\n",
+ sb.s_inodes_count, sb.s_free_inodes_count);
+ printf(" %d groups, %d blocks/group\n",
+ ngroups, sb.s_blocks_per_group);
+ }
+
+ return(0);
+}
+
+int
+ext2_blocksize (void)
+{
+ return blocksize;
+}
+
+int
+ext2_total_blocks (void)
+{
+ return sb.s_blocks_count;
+}
+
+int
+ext2_free_blocks (void)
+{
+ return sb.s_free_blocks_count;
+}
+
+int
+ext2_total_inodes (void)
+{
+ return sb.s_inodes_count;
+}
+
+int
+ext2_free_inodes (void)
+{
+ return sb.s_free_inodes_count;
+}
+
+/* Call this when we're all done with the file system. This will write
+ * back any superblock and group changes to the file system.
+ */
+void
+ext2_close (void)
+{
+ int i;
+ int errors = 0;
+ int blocks_per_group = sb.s_blocks_per_group;
+
+ if(!readonly) {
+
+ if(big_endian) {
+ ext2_swap_sb(&sb);
+ for(i = 0; i < ngroups; i++) {
+ ext2_swap_gd(&(gds[i]));
+ }
+ }
+
+ for(i = 0; i < ngroups; i++) {
+ lseek(fd, ((i*blocks_per_group)+1)*blocksize, SEEK_SET);
+ if(write(fd, &sb, sizeof(sb)) != sizeof(sb)) {
+ perror("sb write");
+ errors = 1;
+ }
+
+ if ((size_t) write(fd, gds, ngroups*sizeof(struct ext2_group_desc))
+ != ngroups*sizeof(struct ext2_group_desc))
+ {
+ perror("gds write");
+ errors = 1;
+ }
+
+ bflush();
+ }
+ }
+
+ close(fd);
+ if(errors) {
+ fprintf(stderr, "Errors encountered while updating %s\n", filename);
+ fprintf(stderr, "e2fsck is STRONGLY recommended!\n");
+ }
+}
+
+
+
+/* Read the specified inode from the disk and return it to the user.
+ * Returns NULL if the inode can't be read...
+ */
+struct ext2_inode *
+ext2_iget (int ino)
+{
+ int i;
+ struct ext2_inode * ip = NULL;
+ struct inode_table_entry * itp = NULL;
+ int group;
+ int blkoffset;
+ int byteoffset;
+ char inobuf[EXT2_MAX_BLOCK_SIZE];
+
+ for(i = 0; i < MAX_OPEN_FILES; i++) {
+ if(inode_table[i].free) {
+ itp = &(inode_table[i]);
+ ip = &(itp->inode);
+ break;
+ }
+ }
+ if(!ip) {
+ fprintf(stderr, "ext2_iget: no free inodes\n");
+ return(NULL);
+ }
+
+ group = ino / sb.s_inodes_per_group;
+ blkoffset = (gds[group].bg_inode_table * blocksize);
+ byteoffset = ((ino-1) % sb.s_inodes_per_group) * sizeof(struct ext2_inode);
+ blkoffset += ((byteoffset / blocksize) * blocksize);
+ byteoffset = (byteoffset % blocksize);
+ bread(blkoffset/blocksize, inobuf);
+
+ memcpy(ip, &(inobuf[byteoffset]), sizeof(struct ext2_inode));
+
+ if(big_endian) {
+ ext2_swap_inode(ip);
+ }
+
+ /* Yes, this is ugly, but it makes iput SOOO much easier 8-) */
+ itp->free = 0;
+ itp->inumber = ino;
+ itp->old_mode = ip->i_mode;
+
+ return(ip);
+}
+
+/* Put the specified inode back on the disk where it came from. */
+void
+ext2_iput (struct ext2_inode *ip)
+{
+ int group;
+ int blkoffset;
+ int byteoffset;
+ int ino;
+ struct inode_table_entry *itp;
+ char inobuf[EXT2_MAX_BLOCK_SIZE];
+ int inode_mode;
+
+ itp = (struct inode_table_entry *)ip;
+ ino = itp->inumber;
+
+ if(ip->i_links_count == 0) {
+ ext2_ifree(itp->inumber);
+ }
+
+ itp->inumber = 0;
+
+ if(!readonly) {
+ group = ino / sb.s_inodes_per_group;
+ blkoffset = (gds[group].bg_inode_table * blocksize);
+ byteoffset = ((ino-1) % sb.s_inodes_per_group) * sizeof(struct ext2_inode);
+ blkoffset += (byteoffset / blocksize) * blocksize;
+ byteoffset = byteoffset % blocksize;
+
+ inode_mode = ip->i_mode;
+ bread(blkoffset/blocksize, inobuf);
+ if(big_endian) {
+ ext2_swap_inode(ip);
+ }
+ memcpy(&(inobuf[byteoffset]), ip, sizeof(struct ext2_inode));
+ bwrite(blkoffset/blocksize, inobuf);
+
+ if(S_ISDIR(itp->old_mode) && !S_ISDIR(inode_mode)) {
+ /* We deleted a directory */
+ gds[group].bg_used_dirs_count--;
+ }
+ if(!S_ISDIR(itp->old_mode) && S_ISDIR(inode_mode)) {
+ /* We created a directory */
+ gds[group].bg_used_dirs_count++;
+ }
+ }
+
+ itp->free = 1;
+}
+
+#define BITS_PER_LONG (8*sizeof(int))
+
+static int
+find_first_zero_bit (unsigned int * addr, unsigned size)
+{
+ unsigned lwsize;
+ unsigned int *ap = (unsigned int *)addr;
+ unsigned int mask;
+ unsigned int longword, bit;
+ unsigned int lwval;
+
+ if (!size)
+ return 0;
+
+ /* Convert "size" to a whole number of longwords... */
+ lwsize = (size + BITS_PER_LONG - 1) >> 5;
+ for (longword = 0; longword < lwsize; longword++, ap++) {
+ if(*ap != 0xffffffff) {
+ lwval = big_endian ? swap32(*ap) : *ap;
+
+ for (bit = 0, mask = 1; bit < BITS_PER_LONG; bit++, mask <<= 1)
+ {
+ if ((lwval & mask) == 0) {
+ return (longword*BITS_PER_LONG) + bit;
+ }
+ }
+ }
+ }
+ return size;
+
+}
+
+static void
+set_bit (unsigned int *addr, int bitno)
+{
+ if(big_endian) {
+ int lwval;
+ lwval = swap32(addr[bitno/BITS_PER_LONG]);
+ lwval |= (1 << (bitno % BITS_PER_LONG));
+ addr[bitno/BITS_PER_LONG] = swap32(lwval);
+ }
+ else {
+ addr[bitno / BITS_PER_LONG] |= (1 << (bitno % BITS_PER_LONG));
+ }
+}
+
+static void
+clear_bit (unsigned int *addr, int bitno)
+{
+ if(big_endian) {
+ int lwval;
+ lwval = swap32(addr[bitno/BITS_PER_LONG]);
+ lwval &= ~((unsigned int)(1 << (bitno % BITS_PER_LONG)));
+ addr[bitno/BITS_PER_LONG] = swap32(lwval);
+ }
+ else {
+ addr[bitno / BITS_PER_LONG] &=
+ ~((unsigned int)(1 << (bitno % BITS_PER_LONG)));
+ }
+}
+
+
+/* Allocate a block from the file system. Brain-damaged implementation;
+ * doesn't even TRY to do load-balancing among groups... just grabs the
+ * first block it can find...
+ */
+int
+ext2_balloc (void)
+{
+ unsigned int blk, blockmap[256];
+ int i;
+
+ if(readonly) {
+ fprintf(stderr, "ext2_balloc: readonly filesystem\n");
+ return(0);
+ }
+
+ for(i = 0; i < ngroups; i++) {
+ if(gds[i].bg_free_blocks_count > 0) {
+ bread(gds[i].bg_block_bitmap, blockmap);
+ blk = find_first_zero_bit(blockmap, sb.s_blocks_per_group);
+ if (blk == 0 || blk == sb.s_blocks_per_group) {
+ fprintf(stderr,
+ "group %d has %d blocks free but none in bitmap?\n",
+ i, gds[i].bg_free_blocks_count);
+ continue;
+ }
+ set_bit(blockmap, blk);
+ bwrite(gds[i].bg_block_bitmap, blockmap);
+ gds[i].bg_free_blocks_count--;
+ sb.s_free_blocks_count--;
+ blk = blk + (i*sb.s_blocks_per_group)+1;
+
+ if(blk == 0) {
+ fprintf(stderr, "ext2_balloc: blk == 0?\n");
+ }
+ return(blk);
+ }
+ }
+
+ if(verbose) {
+ printf("ext2_balloc: can't find a free block\n");
+ }
+ return(0);
+}
+
+/* Deallocate a block */
+void
+ext2_bfree (int blk)
+{
+ int i;
+ unsigned int blockmap[256];
+
+ /* Find which group this block is in */
+ i = (blk-1) / sb.s_blocks_per_group;
+
+ /* Read the block map */
+ bread(gds[i].bg_block_bitmap, blockmap);
+
+ /* Clear the appropriate bit */
+ clear_bit(blockmap, (blk-1) % sb.s_blocks_per_group);
+
+ /* Write the block map back out */
+ bwrite(gds[i].bg_block_bitmap, blockmap);
+
+ /* Update free block counts. */
+ gds[i].bg_free_blocks_count++;
+ sb.s_free_blocks_count++;
+
+}
+
+/* Allocate a contiguous range of blocks. This is used ONLY for
+ * initializing the bootstrapper. It uses a simple-minded algorithm
+ * that works best on a clean or nearly clean file system... we
+ * chunk through the bitmap a longword at a time. Only if the whole
+ * longword indicates free blocks do we use it. On a 32-bit system,
+ * this means we allocate blocks only in units of 32.
+ */
+int
+ext2_contiguous_balloc (int nblocks)
+{
+ int i, j;
+ int firstlong, lastlong;
+ int longs_needed;
+ int longs_per_group;
+ int blk;
+ unsigned int blockmap[256];
+
+ if(readonly) {
+ fprintf(stderr, "ext2_contiguous_balloc: readonly filesystem\n");
+ return(0);
+ }
+
+ /* Compute how many longwords we need to fulfill this request */
+ longs_needed = (nblocks + BITS_PER_LONG - 1) / BITS_PER_LONG;
+ longs_per_group = sb.s_blocks_per_group/BITS_PER_LONG;
+
+ for(i = 0; i < ngroups; i++) {
+ /* Don't even bother if this group doesn't have enough blocks! */
+ if(gds[i].bg_free_blocks_count >= nblocks) {
+
+ /* Get the block map. */
+ bread(gds[i].bg_block_bitmap, blockmap);
+
+ /* Find a run of blocks */
+ firstlong = 0;
+
+ do {
+ for(; firstlong < longs_per_group; firstlong++) {
+ if(blockmap[firstlong] == 0) break;
+ }
+
+ if(firstlong == longs_per_group) {
+ /* No such thing in this group; try another! */
+ break;
+ }
+
+ for(lastlong = firstlong; lastlong < longs_per_group;
+ lastlong++) {
+ if(blockmap[lastlong] != 0) break;
+ }
+
+ if((lastlong-firstlong) < longs_needed) {
+ firstlong = lastlong;
+ }
+ } while((lastlong-firstlong) < longs_needed);
+
+ /* If we got all the way through the block map,
+ * try another group.
+ */
+ if(firstlong == longs_per_group) {
+ continue;
+ }
+
+ /* If we get here, then we know that we have a run
+ * that will fit our allocation. Allocate the *actual*
+ * blocks that we need!
+ */
+ blk = firstlong * BITS_PER_LONG;
+ for(j = 0; j < nblocks; j++) {
+ set_bit(blockmap, blk+j);
+ }
+
+ bwrite(gds[i].bg_block_bitmap, blockmap);
+ gds[i].bg_free_blocks_count -= nblocks;
+ sb.s_free_blocks_count -= nblocks;
+ blk = blk + (i*sb.s_blocks_per_group)+1;
+
+ if(verbose) {
+ printf("ext2_contiguous_balloc: allocated %d blks @%d\n",
+ nblocks, blk);
+ }
+ return(blk);
+ }
+ }
+
+ if(verbose) {
+ printf("ext2_contiguous_balloc: can't find %d contiguous free blocks\n", nblocks);
+ }
+ return(0);
+}
+
+
+/* Pre-allocate contiguous blocks to the specified inode. Note that the
+ * DATA blocks must be contiguous; indirect blocks can come from anywhere.
+ * This is for the benefit of the bootstrap loader.
+ * If successful, this routine returns the block number of the first
+ * data block of the file. Otherwise, it returns -1.
+ */
+int
+ext2_fill_contiguous (struct ext2_inode * ip, int nblocks)
+{
+ int iblkno = 0;
+ int firstblock;
+ int i;
+ unsigned int *lp = NULL;
+ char blkbuf[EXT2_MAX_BLOCK_SIZE];
+
+ /* For simplicity's sake, we only allow single indirection
+ * here. We shouldn't need more than this anyway!
+ */
+ if(nblocks > ind1lim) {
+ fprintf(stderr,
+ "ext2_fill_contiguous: file size too big (%d); cannot exceed %d\n",
+ nblocks, ind1lim);
+ return(-1);
+ }
+
+ /* First, try to allocate the data blocks */
+ firstblock = ext2_contiguous_balloc(nblocks);
+
+ if(firstblock == 0) {
+ fprintf(stderr,
+ "ext2_fill_contiguous: Cannot allocate %d contiguous blocks\n", nblocks);
+ return(-1);
+ }
+
+ ip->i_blocks = nblocks * (blocksize/512);
+
+ /* If we need the indirect block, then allocate it now. */
+ if(nblocks > directlim) {
+ iblkno = ext2_balloc();
+ if(iblkno == 0) {
+ /* Should rarely happen! */
+ fprintf(stderr,
+ "ext2_fill_contiguous: cannot allocate indirect block\n");
+ for(i = 0; i < nblocks; i++) {
+ ext2_bfree(i);
+ }
+ return(-1);
+ }
+ ip->i_blocks += (blocksize/512);
+ /* Point to indirect block buffer, in case we need it! */
+ lp = (unsigned int *)blkbuf;
+
+ for(i = 0; i < ptrs_per_blk; i++) {
+ lp[i] = 0;
+ }
+
+ ip->i_block[EXT2_IND_BLOCK] = iblkno;
+ }
+
+ /* All set... let's roll! */
+ ip->i_size = nblocks * blocksize;
+
+ for(i = 0; i < nblocks; i++) {
+ if(i < EXT2_NDIR_BLOCKS) {
+ ip->i_block[i] = firstblock+i;
+ }
+ else {
+ *lp++ = big_endian ? swap32(firstblock+i) : firstblock+i;
+ }
+ }
+
+ /* Write back the indirect block if necessary... */
+ if(iblkno) {
+ bwrite(iblkno, blkbuf);
+ }
+
+ return(firstblock);
+}
+
+/* Write out a boot block for this file system. The caller
+ * should have instantiated the block.
+ */
+void
+ext2_write_bootblock (char *bb)
+{
+ bwrite(0, bb);
+}
+
+
+/* Allocate an inode from the file system. Brain-damaged implementation;
+ * doesn't even TRY to do load-balancing among groups... just grabs the
+ * first inode it can find...
+ */
+int
+ext2_ialloc (void)
+{
+ unsigned int inodemap[256];
+ int i, ino;
+
+ if(readonly) {
+ return(0);
+ }
+ for(i = 0; i < ngroups; i++) {
+ if(gds[i].bg_free_inodes_count > 4) {
+ /* leave a few inodes in each group for slop... */
+ bread(gds[i].bg_inode_bitmap, inodemap);
+
+ ino = find_first_zero_bit(inodemap, sb.s_inodes_per_group);
+ if (ino == 0 || (unsigned) ino == sb.s_inodes_per_group) {
+ fprintf(stderr,
+ "group %d has %d inodes free but none in bitmap?\n",
+ i, gds[i].bg_free_inodes_count);
+ continue;
+ }
+ set_bit(inodemap, ino);
+ bwrite(gds[i].bg_inode_bitmap, inodemap);
+ gds[i].bg_free_inodes_count--;
+ sb.s_free_inodes_count--;
+ ino = ino + (i*sb.s_inodes_per_group) + 1;
+ return ino;
+ }
+ }
+ return 0;
+}
+
+/* Deallocate an inode */
+static void
+ext2_ifree (int ino)
+{
+ int i;
+ unsigned int inodemap[256];
+
+ /* Find which group this inode is in */
+ i = (ino-1) / sb.s_inodes_per_group;
+
+ /* Read the inode map */
+ bread(gds[i].bg_inode_bitmap, inodemap);
+
+ /* Clear the appropriate bit */
+ clear_bit(inodemap, (ino-1) % sb.s_inodes_per_group);
+
+ /* Write the inode map back out */
+ bwrite(gds[i].bg_inode_bitmap, inodemap);
+
+ /* Update free inode counts. */
+ gds[i].bg_free_inodes_count++;
+ sb.s_free_inodes_count++;
+}
+
+/* Map a block offset into a file into an absolute block number.
+ * (traverse the indirect blocks if necessary). Note: Double-indirect
+ * blocks allow us to map over 64Mb on a 1k file system. Therefore, for
+ * our purposes, we will NOT bother with triple indirect blocks.
+ *
+ * The "allocate" argument is set if we want to *allocate* a block
+ * and we don't already have one allocated.
+ */
+int
+ext2_blkno (struct ext2_inode *ip, int blkoff, int allocate)
+{
+ unsigned int *lp;
+ int blkno;
+ int iblkno;
+ int diblkno;
+ char blkbuf[EXT2_MAX_BLOCK_SIZE];
+
+ if(allocate && readonly) {
+ fprintf(stderr, "ext2_blkno: Cannot allocate on a readonly file system!\n");
+ return(0);
+ }
+
+ lp = (unsigned int *)blkbuf;
+
+ /* If it's a direct block, it's easy! */
+ if(blkoff <= directlim) {
+ if((ip->i_block[blkoff] == 0) && allocate) {
+ ip->i_block[blkoff] = ext2_balloc();
+ if(verbose) {
+ printf("Allocated data block %d\n", ip->i_block[blkoff]);
+ }
+ ip->i_blocks += (blocksize / 512);
+ }
+ return(ip->i_block[blkoff]);
+ }
+
+ /* Is it a single-indirect? */
+ if(blkoff <= ind1lim) {
+ iblkno = ip->i_block[EXT2_IND_BLOCK];
+ if((iblkno == 0) && allocate) {
+ /* No indirect block and we need one, so we allocate
+ * one, zero it, and write it out.
+ */
+ iblkno = ext2_balloc();
+ if(iblkno == 0) {
+ return(0);
+ }
+ ip->i_block[EXT2_IND_BLOCK] = iblkno;
+ if(verbose) {
+ printf("Allocated indirect block %d\n", iblkno);
+ }
+ ip->i_blocks += (blocksize / 512);
+ memset(blkbuf, 0, blocksize);
+ bwrite(iblkno, blkbuf);
+ }
+
+ if(iblkno == 0) {
+ return(0);
+ }
+
+ /* Read the indirect block */
+ bread(iblkno, blkbuf);
+
+ if(big_endian) {
+ blkno = swap32(lp[blkoff-(directlim+1)]);
+ }
+ else {
+ blkno = lp[blkoff-(directlim+1)];
+ }
+ if((blkno == 0) && allocate) {
+ /* No block allocated but we need one. */
+ if(big_endian) {
+ blkno = ext2_balloc();
+ lp[blkoff-(directlim+1)] = swap32(blkno);
+ }
+ else {
+ blkno = lp[blkoff-(directlim+1)] = ext2_balloc();
+ }
+ if(blkno == 0) {
+ return(0);
+ }
+ ip->i_blocks += (blocksize / 512);
+ if(verbose) {
+ printf("Allocated data block %d\n", blkno);
+ }
+ bwrite(iblkno, blkbuf);
+ }
+ return(blkno);
+ }
+
+ /* Is it a double-indirect? */
+ if(blkoff <= ind2lim) {
+ /* Find the double-indirect block */
+ diblkno = ip->i_block[EXT2_DIND_BLOCK];
+ if((diblkno == 0) && allocate) {
+ /* No double-indirect block and we need one. Allocate one,
+ * fill it with zeros, and write it out.
+ */
+ diblkno = ext2_balloc();
+ if(diblkno == 0) {
+ return(0);
+ }
+ ip->i_blocks += (blocksize / 512);
+ if(verbose) {
+ printf("Allocated double-indirect block %d\n", diblkno);
+ }
+ memset(blkbuf, 0, blocksize);
+ bwrite(diblkno, blkbuf);
+ ip->i_block[EXT2_DIND_BLOCK] = diblkno;
+ }
+
+ if(diblkno == 0) {
+ return(0);
+ }
+
+ /* Read in the double-indirect block */
+ bread(diblkno, blkbuf);
+
+ /* Find the single-indirect block pointer ... */
+ iblkno = lp[(blkoff - (ind1lim+1)) / ptrs_per_blk];
+ if(big_endian) {
+ iblkno = swap32(iblkno);
+ }
+
+ if((iblkno == 0) && allocate) {
+ /* No indirect block and we need one, so we allocate
+ * one, zero it, and write it out.
+ */
+ iblkno = ext2_balloc();
+ if(iblkno == 0) {
+ return(0);
+ }
+ ip->i_blocks += (blocksize / 512);
+ if(verbose) {
+ printf("Allocated single-indirect block %d\n", iblkno);
+ }
+ lp[(blkoff-(ind1lim+1)) / ptrs_per_blk] = big_endian ? swap32(iblkno) : iblkno;
+ bwrite(diblkno, blkbuf);
+
+ memset(blkbuf, 0, blocksize);
+ bwrite(iblkno, blkbuf);
+ }
+
+ if(iblkno == 0) {
+ return(0);
+ }
+
+
+ /* Read the indirect block */
+ bread(iblkno, blkbuf);
+
+ /* Find the block itself. */
+ blkno = lp[(blkoff-(ind1lim+1)) % ptrs_per_blk];
+ if(big_endian) {
+ blkno = swap32(blkno);
+ }
+ if((blkno == 0) && allocate) {
+ /* No block allocated but we need one. */
+ if(big_endian) {
+ blkno = ext2_balloc();
+ lp[(blkoff-(ind1lim+1)) % ptrs_per_blk] = swap32(blkno);
+ }
+ else {
+ blkno = lp[(blkoff-(ind1lim+1)) % ptrs_per_blk] = ext2_balloc();
+ }
+ ip->i_blocks += (blocksize / 512);
+ if(verbose) {
+ printf("Allocated data block %d\n", blkno);
+ }
+ bwrite(iblkno, blkbuf);
+ }
+ return(blkno);
+ }
+
+ if(blkoff > ind2lim) {
+ fprintf(stderr, "ext2_blkno: block number too large: %d\n", blkoff);
+ return(0);
+ }
+ return 0;
+}
+
+
+
+
+/* Read block number "blkno" from the specified file */
+void
+ext2_bread (struct ext2_inode *ip, int blkno, char * buffer)
+{
+ int dev_blkno;
+
+ dev_blkno = ext2_blkno(ip, blkno, 0);
+ if(dev_blkno == 0) {
+ /* This is a "hole" */
+ memset(buffer, 0, blocksize);
+ }
+ else {
+ /* Read it for real */
+ bread(dev_blkno, buffer);
+ }
+}
+
+/* Write block number "blkno" to the specified file */
+void
+ext2_bwrite (struct ext2_inode *ip, int blkno, char * buffer)
+{
+ int dev_blkno;
+
+ if(readonly) {
+ fprintf(stderr, "ext2_bwrite: Cannot write to a readonly filesystem!\n");
+ return;
+ }
+
+ dev_blkno = ext2_blkno(ip, blkno, 1);
+ if(dev_blkno == 0) {
+ fprintf(stderr, "%s: No space on ext2 device\n", filename);
+ }
+ else {
+ /* Write it for real */
+ bwrite(dev_blkno, buffer);
+ }
+}
+
+/* More convenient forms of ext2_bread/ext2_bwrite. These allow arbitrary
+ * data alignment and buffer sizes...
+ */
+int
+ext2_seek_and_read (struct ext2_inode *ip, int offset, char *buffer, int count)
+{
+ int blkno;
+ int blkoffset;
+ int bytesleft;
+ int nread;
+ int iosize;
+ char *bufptr;
+ char blkbuf[EXT2_MAX_BLOCK_SIZE];
+
+ bufptr = buffer;
+ bytesleft = count;
+ nread = 0;
+ blkno = offset / blocksize;
+ blkoffset = offset % blocksize;
+
+ while(bytesleft > 0) {
+ iosize = ((blocksize-blkoffset) > bytesleft) ?
+ bytesleft : (blocksize-blkoffset);
+ if((blkoffset == 0) && (iosize == blocksize)) {
+ ext2_bread(ip, blkno, bufptr);
+ }
+ else {
+ ext2_bread(ip, blkno, blkbuf);
+ memcpy(bufptr, blkbuf+blkoffset, iosize);
+ }
+ bytesleft -= iosize;
+ bufptr += iosize;
+ nread += iosize;
+ blkno++;
+ blkoffset = 0;
+ }
+ return(nread);
+}
+
+int
+ext2_seek_and_write (struct ext2_inode *ip, int offset, char *buffer, int count)
+{
+ int blkno;
+ int blkoffset;
+ int bytesleft;
+ int nwritten;
+ int iosize;
+ char *bufptr;
+ char blkbuf[EXT2_MAX_BLOCK_SIZE];
+
+ bufptr = buffer;
+ bytesleft = count;
+ nwritten = 0;
+ blkno = offset / blocksize;
+ blkoffset = offset % blocksize;
+
+ while(bytesleft > 0) {
+ iosize = ((blocksize-blkoffset) > bytesleft) ?
+ bytesleft : (blocksize-blkoffset);
+ if((blkoffset == 0) && (iosize == blocksize)) {
+ ext2_bwrite(ip, blkno, bufptr);
+ }
+ else {
+ ext2_bread(ip, blkno, blkbuf);
+ memcpy(blkbuf+blkoffset, bufptr, iosize);
+ ext2_bwrite(ip, blkno, blkbuf);
+ }
+ bytesleft -= iosize;
+ bufptr += iosize;
+ nwritten += iosize;
+ blkno++;
+ blkoffset = 0;
+ }
+ return(nwritten);
+}
+
+struct ext2_inode *
+ext2_namei (char *name)
+{
+ char namebuf[256];
+ char dirbuf[EXT2_MAX_BLOCK_SIZE];
+ char * component;
+ struct ext2_inode * dir_inode;
+ struct ext2_dir_entry *dp;
+ int next_ino;
+
+ /* Squirrel away a copy of "namebuf" that we can molest */
+ strcpy(namebuf, name);
+
+ /* Start at the root... */
+ dir_inode = ext2_iget(EXT2_ROOT_INO);
+
+ component = strtok(namebuf, "/");
+ while(component) {
+ unsigned diroffset;
+ int component_length, blockoffset;
+
+ /* Search for the specified component in the current directory
+ * inode.
+ */
+
+ next_ino = -1;
+
+ component_length = strlen(component);
+ diroffset = 0;
+ while (diroffset < dir_inode->i_size) {
+ blockoffset = 0;
+ ext2_bread(dir_inode, diroffset / blocksize, dirbuf);
+ while (blockoffset < blocksize) {
+ int namelen;
+
+ dp = (struct ext2_dir_entry *)(dirbuf+blockoffset);
+ namelen = big_endian ? swap16(dp->name_len) : dp->name_len;
+ if((namelen == component_length) &&
+ (strncmp(component, dp->name, component_length) == 0)) {
+ /* Found it! */
+ next_ino = big_endian ? swap32(dp->inode) : dp->inode;
+ break;
+ }
+ /* Go to next entry in this block */
+ blockoffset += (big_endian ? swap16(dp->rec_len) : dp->rec_len);
+ }
+ if(next_ino >= 0) {
+ break;
+ }
+
+ /* If we got here, then we didn't find the component.
+ * Try the next block in this directory...
+ */
+ diroffset += blocksize;
+ }
+
+ /* At this point, we're done with this directory whether
+ * we've succeeded or failed...
+ */
+ ext2_iput(dir_inode);
+
+ /* If next_ino is negative, then we've failed (gone all the
+ * way through without finding anything)
+ */
+ if(next_ino < 0) {
+ return(NULL);
+ }
+
+ /* Otherwise, we can get this inode and find the next
+ * component string...
+ */
+ dir_inode = ext2_iget(next_ino);
+
+ component = strtok(NULL, "/");
+ }
+
+ /* If we get here, then we got through all the components.
+ * Whatever we got must match up with the last one.
+ */
+ return(dir_inode);
+}
+
+/* Create a new entry in the specified directory with the specified
+ * name/inumber pair. This routine ASSUMES that the specified
+ * entry does not already exist! Therefore, we MUST use namei
+ * first to try and find the entry...
+ */
+
+void
+ext2_mknod (struct ext2_inode *dip, char * name, int ino)
+{
+ unsigned diroffset;
+ int blockoffset, namelen, new_reclen;
+ struct ext2_dir_entry *dp;
+ struct ext2_dir_entry *entry_dp;
+ char dirbuf[EXT2_MAX_BLOCK_SIZE];
+ int dp_inode, dp_reclen, dp_namelen;
+
+ namelen = strlen(name);
+
+ /* Look for an empty directory entry that can hold this
+ * item.
+ */
+ diroffset = 0;
+ entry_dp = NULL;
+ while (diroffset < dip->i_size) {
+ blockoffset = 0;
+ ext2_bread(dip, diroffset / blocksize, dirbuf);
+ while(blockoffset < blocksize) {
+
+ dp = (struct ext2_dir_entry *)(dirbuf+blockoffset);
+ dp_inode = big_endian ? swap32(dp->inode) : dp->inode;
+ dp_reclen = big_endian ? swap16(dp->rec_len) : dp->rec_len;
+ dp_namelen = big_endian ? swap16(dp->name_len) : dp->name_len;
+
+ if((dp_inode == 0) && (dp_reclen >= EXT2_DIR_REC_LEN(namelen))) {
+ /* Found an *empty* entry that can hold this name. */
+ entry_dp = dp;
+ break;
+ }
+
+ /* If this entry is in use, see if it has space at the end
+ * to hold the new entry anyway...
+ */
+ if((dp_inode != 0) &&
+ ((dp_reclen - EXT2_DIR_REC_LEN(dp_namelen))
+ >= EXT2_DIR_REC_LEN(namelen))) {
+
+ new_reclen = dp_reclen - EXT2_DIR_REC_LEN(dp_namelen);
+
+ /* Chop the in-use entry down to size */
+ if(big_endian) {
+ dp_reclen = EXT2_DIR_REC_LEN(swap16(dp->name_len));
+ }
+ else {
+ dp_reclen = EXT2_DIR_REC_LEN(dp->name_len);
+ }
+ dp->rec_len = big_endian ? swap16(dp_reclen) : dp_reclen;
+
+ /* Point entry_dp to the end of this entry */
+ entry_dp = (struct ext2_dir_entry *)((char*)dp + dp_reclen);
+
+ /* Set the record length for this entry */
+ entry_dp->rec_len = big_endian ? swap16(new_reclen) : new_reclen;
+
+ /* all set! */
+ break;
+ }
+
+ /* No luck yet... go to next entry in this block */
+ blockoffset += dp_reclen;
+ }
+ if(entry_dp != NULL) {
+ break;
+ }
+
+ /* If we got here, then we didn't find the component.
+ * Try the next block in this directory...
+ */
+ diroffset += blocksize;
+ }
+
+ /* By the time we get here, one of two things has happened:
+ *
+ * If entry_dp is non-NULL, then entry_dp points to the
+ * place in dirbuf where the entry lives, and diroffset
+ * is the directory offset of the beginning of dirbuf.
+ *
+ * If entry_dp is NULL, then we couldn't find an entry,
+ * so we need to add a block to the directory file for
+ * this entry...
+ */
+ if(entry_dp) {
+ entry_dp->inode = big_endian ? swap32(ino) : ino;
+ entry_dp->name_len = big_endian ? swap16(namelen) : namelen;
+ strncpy(entry_dp->name, name, namelen);
+ ext2_bwrite(dip, diroffset/blocksize, dirbuf);
+ }
+ else {
+ entry_dp = (struct ext2_dir_entry *)dirbuf;
+ entry_dp->inode = big_endian ? swap32(ino) : ino;
+ entry_dp->name_len = big_endian ? swap16(namelen) : namelen;
+ strncpy(entry_dp->name, name, namelen);
+ entry_dp->rec_len = big_endian ? swap16(blocksize) : blocksize;
+ ext2_bwrite(dip, dip->i_size/blocksize, dirbuf);
+ dip->i_size += blocksize;
+ }
+}
+
+/* This is a close cousin to namei, only it *removes* the entry
+ * in addition to finding it. This routine assumes that the specified
+ * entry has already been found...
+ */
+void
+ext2_remove_entry (char *name)
+{
+ char namebuf[256];
+ char dirbuf[EXT2_MAX_BLOCK_SIZE];
+ char * component;
+ struct ext2_inode * dir_inode;
+ struct ext2_dir_entry *dp;
+ int next_ino;
+ int dp_inode, dp_reclen, dp_namelen;
+
+ /* Squirrel away a copy of "namebuf" that we can molest */
+ strcpy(namebuf, name);
+
+ /* Start at the root... */
+ dir_inode = ext2_iget(EXT2_ROOT_INO);
+
+ component = strtok(namebuf, "/");
+ while(component) {
+ unsigned diroffset;
+ int blockoffset, component_length;
+ char *next_component;
+ struct ext2_dir_entry * pdp;
+
+ /* Search for the specified component in the current directory
+ * inode.
+ */
+
+ next_component = NULL;
+ pdp = NULL;
+ next_ino = -1;
+
+ component_length = strlen(component);
+ diroffset = 0;
+ while (diroffset < dir_inode->i_size) {
+ blockoffset = 0;
+ ext2_bread(dir_inode, diroffset / blocksize, dirbuf);
+ while(blockoffset < blocksize) {
+ dp = (struct ext2_dir_entry *)(dirbuf+blockoffset);
+ dp_inode = big_endian ? swap32(dp->inode) : dp->inode;
+ dp_reclen = big_endian ? swap16(dp->rec_len) : dp->rec_len;
+ dp_namelen = big_endian ? swap16(dp->name_len) : dp->name_len;
+
+ if((dp_namelen == component_length) &&
+ (strncmp(component, dp->name, component_length) == 0)) {
+ /* Found it! */
+ next_component = strtok(NULL, "/");
+ if(next_component == NULL) {
+ /* We've found the entry that needs to be
+ * zapped. If it's at the beginning of the
+ * block, then zap it. Otherwise, coalesce
+ * it with the previous entry.
+ */
+ if(pdp) {
+ if(big_endian) {
+ pdp->rec_len =
+ swap16(swap16(pdp->rec_len)+dp_reclen);
+ }
+ else {
+ pdp->rec_len += dp_reclen;
+ }
+ }
+ else {
+ dp->inode = 0;
+ dp->name_len = 0;
+ }
+ ext2_bwrite(dir_inode, diroffset / blocksize, dirbuf);
+ return;
+ }
+ next_ino = dp_inode;
+ break;
+ }
+ /* Go to next entry in this block */
+ pdp = dp;
+ blockoffset += dp_reclen;
+ }
+ if(next_ino >= 0) {
+ break;
+ }
+
+ /* If we got here, then we didn't find the component.
+ * Try the next block in this directory...
+ */
+ diroffset += blocksize;
+ }
+
+ /* At this point, we're done with this directory whether
+ * we've succeeded or failed...
+ */
+ ext2_iput(dir_inode);
+
+ /* If next_ino is negative, then we've failed (gone all the
+ * way through without finding anything)
+ */
+ if(next_ino < 0) {
+ return;
+ }
+
+ /* Otherwise, we can get this inode and find the next
+ * component string...
+ */
+ dir_inode = ext2_iget(next_ino);
+
+ component = next_component;
+ }
+
+ ext2_iput(dir_inode);
+}
+
+
+void
+ext2_truncate (struct ext2_inode *ip)
+{
+ int i;
+
+ /* Deallocate all blocks associated with a particular file
+ * and set its size to zero.
+ */
+
+ /* Direct blocks */
+ for(i = 0; i < EXT2_NDIR_BLOCKS; i++) {
+ if(ip->i_block[i]) {
+ ext2_bfree(ip->i_block[i]);
+ ip->i_block[i] = 0;
+ }
+ }
+
+ /* First-level indirect blocks */
+ if(ip->i_block[EXT2_IND_BLOCK]) {
+ ext2_free_indirect(ip->i_block[EXT2_IND_BLOCK], 0);
+ ip->i_block[EXT2_IND_BLOCK] = 0;
+ }
+
+ /* Second-level indirect blocks */
+ if(ip->i_block[EXT2_DIND_BLOCK]) {
+ ext2_free_indirect(ip->i_block[EXT2_DIND_BLOCK], 1);
+ ip->i_block[EXT2_DIND_BLOCK] = 0;
+ }
+
+ /* Third-level indirect blocks */
+ if(ip->i_block[EXT2_TIND_BLOCK]) {
+ ext2_free_indirect(ip->i_block[EXT2_TIND_BLOCK], 2);
+ ip->i_block[EXT2_TIND_BLOCK] = 0;
+ }
+
+ ip->i_size = 0;
+}
+
+/* Recursive routine to free an indirect chain */
+static void
+ext2_free_indirect (int indirect_blkno, int level)
+{
+ int i, indirect_block[EXT2_MAX_BLOCK_SIZE/4];
+
+ /* Read the specified indirect block */
+ bread(indirect_blkno, indirect_block);
+
+ for(i = 0; i < ptrs_per_blk; i++) {
+ if(level == 0) {
+ /* These are pointers to data blocks; just free them up */
+ if(indirect_block[i]) {
+ if(big_endian) {
+ ext2_bfree(swap32(indirect_block[i]));
+ }
+ else {
+ ext2_bfree(indirect_block[i]);
+ }
+ indirect_block[i] = 0;
+ }
+ }
+ else {
+ /* These are pointers to *indirect* blocks. Go down the chain */
+ if(indirect_block[i]) {
+ if(big_endian) {
+ ext2_free_indirect(swap32(indirect_block[i]), level-1);
+ }
+ else {
+ ext2_free_indirect(indirect_block[i], level-1);
+ }
+ indirect_block[i] = 0;
+ }
+ }
+ }
+ ext2_bfree(indirect_blkno);
+}
+
+int
+ext2_get_inumber (struct ext2_inode *ip)
+{
+ struct inode_table_entry *itp;
+
+ itp = (struct inode_table_entry *)ip;
+ return(itp->inumber);
+}
diff --git a/package/aboot/src/tools/e2lib.h b/package/aboot/src/tools/e2lib.h
new file mode 100644
index 000000000..7c94ce270
--- /dev/null
+++ b/package/aboot/src/tools/e2lib.h
@@ -0,0 +1,332 @@
+#ifndef EXT2_LIB_H
+#define EXT2_LIB_H
+
+#include <fcntl.h>
+
+
+/* Definitions cribbed from ext2_fs.h, modified so's to be 64-bit clean
+ * when cross-compiling on Alpha
+ */
+
+/*
+ * The second extended filesystem constants/structures
+ */
+
+/*
+ * Define EXT2FS_DEBUG to produce debug messages
+ */
+#undef EXT2FS_DEBUG
+
+/*
+ * Define EXT2FS_DEBUG_CACHE to produce cache debug messages
+ */
+#undef EXT2FS_DEBUG_CACHE
+
+/*
+ * Define EXT2FS_CHECK_CACHE to add some checks to the name cache code
+ */
+#undef EXT2FS_CHECK_CACHE
+
+/*
+ * Define EXT2FS_PRE_02B_COMPAT to convert ext 2 fs prior to 0.2b
+ */
+#undef EXT2FS_PRE_02B_COMPAT
+
+/*
+ * Define DONT_USE_DCACHE to inhibit the directory cache
+ */
+#define DONT_USE_DCACHE
+
+/*
+ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
+ */
+#define EXT2_PREALLOCATE
+
+/*
+ * The second extended file system version
+ */
+#define EXT2FS_DATE "94/03/10"
+#define EXT2FS_VERSION "0.5"
+
+
+/*
+ * Special inodes numbers
+ */
+#define EXT2_BAD_INO 1 /* Bad blocks inode */
+#define EXT2_ROOT_INO 2 /* Root inode */
+#define EXT2_ACL_IDX_INO 3 /* ACL inode */
+#define EXT2_ACL_DATA_INO 4 /* ACL inode */
+#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
+#define EXT2_FIRST_INO 11 /* First non reserved inode */
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_PRE_02B_MAGIC 0xEF51
+#define EXT2_SUPER_MAGIC 0xEF53
+#define EXT2_SUPER_BIGMAGIC 0x53EF /* Accessing on big-endian system... */
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT2_LINK_MAX 32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_SIZE 1024
+#define EXT2_MAX_BLOCK_SIZE 4096
+#define EXT2_MIN_BLOCK_LOG_SIZE 10
+# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (unsigned int))
+# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode))
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT2_MIN_FRAG_SIZE 1024
+#define EXT2_MAX_FRAG_SIZE 4096
+#define EXT2_MIN_FRAG_LOG_SIZE 10
+# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
+# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
+
+/*
+ * ACL structures
+ */
+struct ext2_acl_header /* Header of Access Control Lists */
+{
+ unsigned int aclh_size;
+ unsigned int aclh_file_count;
+ unsigned int aclh_acle_count;
+ unsigned int aclh_first_acle;
+};
+
+struct ext2_acl_entry /* Access Control List Entry */
+{
+ unsigned int acle_size;
+ unsigned short acle_perms; /* Access permissions */
+ unsigned short acle_type; /* Type of entry */
+ unsigned short acle_tag; /* User or group identity */
+ unsigned short acle_pad1;
+ unsigned int acle_next; /* Pointer on next entry for the */
+ /* same inode or on next free entry */
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_old_group_desc
+{
+ unsigned int bg_block_bitmap; /* Blocks bitmap block */
+ unsigned int bg_inode_bitmap; /* Inodes bitmap block */
+ unsigned int bg_inode_table; /* Inodes table block */
+ unsigned short bg_free_blocks_count; /* Free blocks count */
+ unsigned short bg_free_inodes_count; /* Free inodes count */
+};
+
+struct ext2_group_desc
+{
+ unsigned int bg_block_bitmap; /* Blocks bitmap block */
+ unsigned int bg_inode_bitmap; /* Inodes bitmap block */
+ unsigned int bg_inode_table; /* Inodes table block */
+ unsigned short bg_free_blocks_count; /* Free blocks count */
+ unsigned short bg_free_inodes_count; /* Free inodes count */
+ unsigned short bg_used_dirs_count; /* Directories count */
+ unsigned short bg_pad;
+ unsigned int bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
+# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL 0x0001 /* Secure deletion */
+#define EXT2_UNRM_FL 0x0002 /* Undelete */
+#define EXT2_COMPR_FL 0x0004 /* Compress file */
+#define EXT2_SYNC_FL 0x0008 /* Synchronous updates */
+
+/*
+ * ioctl commands
+ */
+#define EXT2_IOC_GETFLAGS _IOR('f', 1, int)
+#define EXT2_IOC_SETFLAGS _IOW('f', 2, int)
+#define EXT2_IOC_GETVERSION _IOR('v', 1, int)
+#define EXT2_IOC_SETVERSION _IOW('v', 2, int)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+ unsigned short i_mode; /* File mode */
+ unsigned short i_uid; /* Owner Uid */
+ unsigned int i_size; /* Size in bytes */
+ unsigned int i_atime; /* Access time */
+ unsigned int i_ctime; /* Creation time */
+ unsigned int i_mtime; /* Modification time */
+ unsigned int i_dtime; /* Deletion Time */
+ unsigned short i_gid; /* Group Id */
+ unsigned short i_links_count; /* Links count */
+ unsigned int i_blocks; /* Blocks count */
+ unsigned int i_flags; /* File flags */
+ unsigned int i_reserved1;
+ unsigned int i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ unsigned int i_version; /* File version (for NFS) */
+ unsigned int i_file_acl; /* File ACL */
+ unsigned int i_dir_acl; /* Directory ACL */
+ unsigned int i_faddr; /* Fragment address */
+ unsigned char i_frag; /* Fragment number */
+ unsigned char i_fsize; /* Fragment size */
+ unsigned short i_pad1;
+ unsigned int i_reserved2[2];
+};
+
+/*
+ * File system states
+ */
+#define EXT2_VALID_FS 0x0001 /* Unmounted cleany */
+#define EXT2_ERROR_FS 0x0002 /* Errors detected */
+
+/*
+ * Mount flags
+ */
+#define EXT2_MOUNT_CHECK_NORMAL 0x0001 /* Do some more checks */
+#define EXT2_MOUNT_CHECK_STRICT 0x0002 /* Do again more checks */
+#define EXT2_MOUNT_CHECK (EXT2_MOUNT_CHECK_NORMAL | \
+ EXT2_MOUNT_CHECK_STRICT)
+#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
+
+#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \
+ EXT2_MOUNT_##opt)
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC 3 /* Panic */
+#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ unsigned int s_inodes_count; /* 0: Inodes count */
+ unsigned int s_blocks_count; /* 4: Blocks count */
+ unsigned int s_r_blocks_count;/* 8: Reserved blocks count */
+ unsigned int s_free_blocks_count;/* 12: Free blocks count */
+ unsigned int s_free_inodes_count;/* 16: Free inodes count */
+ unsigned int s_first_data_block;/* 20: First Data Block */
+ unsigned int s_log_block_size;/* 24: Block size */
+ int s_log_frag_size; /* 28: Fragment size */
+ unsigned int s_blocks_per_group;/* 32: # Blocks per group */
+ unsigned int s_frags_per_group;/* 36: # Fragments per group */
+ unsigned int s_inodes_per_group;/* 40: # Inodes per group */
+ unsigned int s_mtime; /* 44: Mount time */
+ unsigned int s_wtime; /* 48: Write time */
+ unsigned short s_mnt_count; /* 52: Mount count */
+ short s_max_mnt_count; /* 54: Maximal mount count */
+ unsigned short s_magic; /* 56: Magic signature */
+ unsigned short s_state; /* 58: File system state */
+ unsigned short s_errors; /* 60: Behaviour when detecting errors */
+ unsigned short s_pad; /* 62: */
+ unsigned int s_lastcheck; /* 64: time of last check */
+ unsigned int s_checkinterval; /* 68: max. time between checks */
+ unsigned int s_reserved[238]; /* 72: Padding to the end of the block */
+};
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+ unsigned int inode; /* Inode number */
+ unsigned short rec_len; /* Directory entry length */
+ unsigned short name_len; /* Name length */
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+
+
+/* These definitions are cribbed from other file system include files, so that
+ * we can take a stab at identifying non-ext2 file systems as well...
+ */
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+ unsigned short s_ninodes;
+ unsigned short s_nzones;
+ unsigned short s_imap_blocks;
+ unsigned short s_zmap_blocks;
+ unsigned short s_firstdatazone;
+ unsigned short s_log_zone_size;
+ unsigned int s_max_size;
+ unsigned short s_magic;
+ unsigned short s_state;
+};
+
+#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
+#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
+#define NEW_MINIX_SUPER_MAGIC 0x2468 /* minix V2 - not implemented */
+
+extern int ext2_init(char * name, int access);
+extern void ext2_close();
+extern struct ext2_inode * ext2_iget(int ino);
+extern void ext2_iput(struct ext2_inode *ip);
+extern int ext2_balloc(void);
+extern int ext2_ialloc(void);
+extern int ext2_blocksize(void);
+extern int ext2_blkno(struct ext2_inode *ip, int blkoff,
+ int allocate);
+extern void ext2_bread(struct ext2_inode *ip, int blkno,
+ char * buffer);
+extern void ext2_bwrite(struct ext2_inode *ip, int blkno,
+ char * buffer);
+extern struct ext2_inode * ext2_namei(char * name);
+extern void ext2_truncate(struct ext2_inode *ip);
+extern void ext2_mknod(struct ext2_inode *dip,
+ char * name, int ino);
+extern int ext2_fill_contiguous(struct ext2_inode * ip,
+ int nblocks);
+extern void ext2_write_bootblock(char *bb);
+
+#endif /* EXT2_LIB_H */
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;
+}
diff --git a/package/aboot/src/tools/elfencap.c b/package/aboot/src/tools/elfencap.c
new file mode 100644
index 000000000..3e5f4b4b9
--- /dev/null
+++ b/package/aboot/src/tools/elfencap.c
@@ -0,0 +1,61 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/stat.h>
+
+#include <linux/elf.h>
+
+
+int
+main (int argc, char ** argv)
+{
+ int ifd;
+ ssize_t n;
+ char buf[8192];
+ struct stat st;
+ struct {
+ struct elf64_hdr ehdr;
+ struct elf64_phdr phdr;
+ } h;
+
+ ifd = open(argv[1], O_RDONLY);
+ if (ifd < 0) {
+ perror(argv[1]);
+ return 1;
+ }
+
+ if (fstat(ifd, &st) < 0) {
+ perror(argv[1]);
+ return 1;
+ }
+
+ memset(&h, 0, sizeof(h));
+
+ h.ehdr.e_ident[0] = 0x7f;
+ strcpy(h.ehdr.e_ident + 1, "ELF");
+ h.ehdr.e_ident[EI_CLASS] = ELFCLASS64;
+ h.ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+ h.ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ h.ehdr.e_type = ET_EXEC;
+ h.ehdr.e_machine = EM_ALPHA;
+ h.ehdr.e_version = EV_CURRENT;
+ h.ehdr.e_entry = 0xfffffc0000310000;
+ h.ehdr.e_phnum = 1;
+ h.ehdr.e_phoff = (char *) &h.phdr - (char *) &h;
+ h.phdr.p_vaddr = 0xfffffc0000310000;
+ h.phdr.p_offset = sizeof(h);
+ h.phdr.p_filesz = st.st_size;
+ h.phdr.p_memsz = h.phdr.p_filesz;
+
+ write(1, &h, sizeof(h));
+
+ while ((n = read(ifd, buf, sizeof(buf))) > 0) {
+ if (write(1, buf, n) != n) {
+ perror("short write");
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/package/aboot/src/tools/isomarkboot.c b/package/aboot/src/tools/isomarkboot.c
new file mode 100644
index 000000000..ba01009fa
--- /dev/null
+++ b/package/aboot/src/tools/isomarkboot.c
@@ -0,0 +1,239 @@
+/*
+ * isomarkboot.c
+ *
+ * This file is part of aboot, the SRM bootloader for Linux/Alpha
+ * Copyright (C) 1996 David Mosberger.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * Making an ISO9660 filesystem bootable is straight-forward since all
+ * files are contiguous.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <asm/fcntl.h>
+
+#include <config.h>
+#include <isolib.h>
+#include <iso.h>
+
+const char * prog_name;
+
+static int disk;
+
+void
+__memcpy (void * dest, const void * src, size_t n)
+{
+ memcpy (dest, src, n);
+}
+
+long
+iso_dev_read (void * buf, long offset, long size)
+{
+ if (lseek(disk, offset, SEEK_SET) != offset) {
+ perror("lseek");
+ return -1;
+ }
+ return read(disk, buf, size);
+}
+
+/* Write a 64-bit quantity out into memory in LITTLE ENDIAN order */
+static void write_64 (unsigned char* out, unsigned long long in)
+{
+ out[0] = in & 0xFF;
+ out[1] = (in >> 8) & 0xFF;
+ out[2] = (in >> 16) & 0xFF;
+ out[3] = (in >> 24) & 0xFF;
+ out[4] = (in >> 32) & 0xFF;
+ out[5] = (in >> 40) & 0xFF;
+ out[6] = (in >> 48) & 0xFF;
+ out[7] = (in >> 56) & 0xFF;
+}
+
+/* Read in a 64-bit LITTLE ENDIAN quantity */
+static unsigned long long read_64 (unsigned char *in)
+{
+ unsigned long long result = 0;
+
+ result |= (unsigned long long) in[0];
+ result |= (unsigned long long) in[1] << 8;
+ result |= (unsigned long long) in[2] << 16;
+ result |= (unsigned long long) in[3] << 24;
+ result |= (unsigned long long) in[4] << 32;
+ result |= (unsigned long long) in[5] << 40;
+ result |= (unsigned long long) in[6] << 48;
+ result |= (unsigned long long) in[7] << 56;
+
+ return result;
+}
+
+int
+main (int argc, char ** argv)
+{
+ u_int64_t sector[512 / 8], sum;
+ struct iso_primary_descriptor vol_desc;
+ size_t nbytes, aboot_size;
+ off_t aboot_pos;
+ int i, aboot_fd;
+ int rootbin_fd;
+ off_t rootbin_pos;
+ char root_start[100];
+
+ prog_name = argv[0];
+
+ if (argc < 3 || argc > 4) {
+ fprintf(stderr, "usage: %s filesys path [root.bin]\n", prog_name);
+ exit(1);
+ }
+ disk = open(argv[1], O_RDWR);
+ if (disk < 0) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ if (iso_read_super (0, 0) < 0) {
+ fprintf(stderr, "%s: cannot mount\n", argv[1]);
+ exit(1);
+ }
+
+ aboot_fd = iso_open(argv[2]);
+ if (aboot_fd < 0) {
+ fprintf(stderr, "%s: file not found\n", argv[2]);
+ exit(1);
+ }
+
+ {
+ struct stat buf;
+ iso_fstat(aboot_fd, &buf);
+ aboot_size = buf.st_size;
+ }
+
+ aboot_pos = iso_map (aboot_fd, 0);
+
+ printf("%s: %s is at offset %ld and is %lu bytes long\n",
+ prog_name, argv[2], aboot_pos, aboot_size);
+
+ if (lseek(disk, 0, SEEK_SET) != 0) {
+ perror("lseek");
+ return -1;
+ }
+
+ nbytes = read(disk, sector, sizeof(sector));
+ if (nbytes != sizeof(sector)) {
+ if ((long) nbytes < 0) {
+ perror("read");
+ } else {
+ fprintf(stderr, "%s: short read\n", prog_name);
+ }
+ exit(1);
+ }
+
+ strcpy((char *) sector, "Linux/Alpha aboot for ISO filesystem.");
+ write_64 ((unsigned char *) &sector[60], aboot_size / 512);/* sector count */
+ write_64 ((unsigned char *) &sector[61], aboot_pos / 512); /* starting LBM */
+ write_64 ((unsigned char *) &sector[62], 0); /* flags */
+
+ /* update checksum: */
+ sum = 0;
+ for (i = 0; i < 63; i++)
+ sum += read_64 ((unsigned char *) &sector[i]);
+
+ write_64 ((unsigned char *) &sector[63], sum);
+
+ if (lseek(disk, 0, SEEK_SET) != 0) {
+ perror("lseek");
+ return -1;
+ }
+
+ nbytes = write(disk, sector, sizeof(sector));
+ if (nbytes != sizeof(sector)) {
+ if ((long) nbytes < 0) {
+ perror("write");
+ } else {
+ fprintf(stderr, "%s: short write\n", prog_name);
+ }
+ exit(1);
+ }
+
+ if (argc < 4)
+ return 0;
+
+ rootbin_fd = iso_open(argv[3]);
+ if (rootbin_fd < 0) {
+ fprintf(stderr, "%s: file not found\n", argv[3]);
+ exit(1);
+ }
+
+ rootbin_pos = iso_map (rootbin_fd, 0);
+ iso_close(rootbin_fd);
+
+ {
+ struct stat buf;
+ iso_fstat(rootbin_fd, &buf);
+ printf("%s: %s is at offset %ld and is %lu bytes long\n",
+ prog_name, argv[3], rootbin_pos, buf.st_size);
+ }
+
+
+ if (lseek(disk, 16*2048, SEEK_SET) != 16*2048) {
+ perror("lseek");
+ return -1;
+ }
+ nbytes = read(disk, &vol_desc, sizeof(vol_desc));
+ if (nbytes != sizeof(vol_desc)) {
+ if ((long) nbytes < 0) {
+ perror("read");
+ } else {
+ fprintf(stderr, "%s: short read\n", prog_name);
+ }
+ exit(1);
+ }
+
+ if (strncmp (vol_desc.id, ISO_STANDARD_ID, sizeof vol_desc.id) != 0) {
+ fprintf(stderr,"first volume descriptor has not an ISO_STANDARD_ID!!\n");
+ exit(1);
+ }
+ if (isonum_711 (vol_desc.type) != ISO_VD_PRIMARY) {
+ fprintf(stderr,"first volume descriptor is not a primary one!!\n");
+ exit(1);
+ }
+ if (rootbin_pos & 2047) {
+ fprintf(stderr,"erreur:rootbin_pos=%ld is not at a isoblock boundary\n",rootbin_pos);
+ exit(1);
+ }
+ sprintf(root_start,"ROOT START=%ld ",rootbin_pos/2048);
+ printf("writing %s in application_data of first volume descriptor\n", root_start);
+ memcpy(vol_desc.application_data,root_start,strlen(root_start));
+ if (lseek(disk, 16*2048, SEEK_SET) != 16*2048) {
+ perror("lseek");
+ return -1;
+ }
+
+ nbytes = write(disk, &vol_desc, sizeof(vol_desc));
+ if (nbytes != sizeof(vol_desc)) {
+ if ((long) nbytes < 0) {
+ perror("write");
+ } else {
+ fprintf(stderr, "%s: short write\n", prog_name);
+ }
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/package/aboot/src/tools/objstrip.c b/package/aboot/src/tools/objstrip.c
new file mode 100644
index 000000000..19612644b
--- /dev/null
+++ b/package/aboot/src/tools/objstrip.c
@@ -0,0 +1,260 @@
+/*
+ * arch/alpha/boot/tools/objstrip.c
+ *
+ * Strip the object file headers/trailers from an executable (ELF).
+ *
+ * Copyright (C) 1996 David Mosberger-Tang.
+ */
+/*
+ * Converts an ELF object file into a bootable file. The
+ * object file must be a OMAGIC file (i.e., data and bss follow immediatly
+ * behind the text). See DEC "Assembly Language Programmer's Guide"
+ * documentation for details. The SRM boot process is documented in
+ * the Alpha AXP Architecture Reference Manual, Second Edition by
+ * Richard L. Sites and Richard T. Witek.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <a.out.h>
+#include <linux/coff.h>
+#include <linux/param.h>
+#include <string.h>
+
+#ifdef __ELF__
+# include <linux/elf.h>
+# include <linux/version.h>
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+# define elf_check_arch(x) ((x)->e_machine == EM_ALPHA)
+# endif
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+# define aboot_elf_check_arch(e) elf_check_arch(e)
+# else
+# define aboot_elf_check_arch(e) elf_check_arch(e->e_machine)
+# endif
+#endif
+
+/* bootfile size must be multiple of BLOCK_SIZE: */
+#define BLOCK_SIZE 512
+
+const char * prog_name;
+
+
+void
+usage (void)
+{
+ fprintf(stderr,
+ "usage: %s [-v] -p file primary\n"
+ " %s [-vb] file [secondary]\n", prog_name, prog_name);
+ exit(1);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ size_t nwritten, tocopy, n, mem_size, fil_size, pad = 0;
+ int fd, ofd, i, j, verbose = 0, primary = 0;
+ char buf[8192], *inname;
+ struct exec * aout; /* includes file & aout header */
+ long offset;
+#ifdef __ELF__
+ struct elf64_hdr *elf;
+ struct elf64_phdr *elf_phdr; /* program header */
+ unsigned long long e_entry;
+#endif
+
+ prog_name = argv[0];
+
+ for (i = 1; i < argc && argv[i][0] == '-'; ++i) {
+ for (j = 1; argv[i][j]; ++j) {
+ switch (argv[i][j]) {
+ case 'v':
+ verbose = ~verbose;
+ break;
+
+ case 'b':
+ pad = BLOCK_SIZE;
+ break;
+
+ case 'p':
+ primary = 1; /* make primary bootblock */
+ break;
+ }
+ }
+ }
+
+ if (i >= argc) {
+ usage();
+ }
+ inname = argv[i++];
+
+ fd = open(inname, O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ exit(1);
+ }
+
+ ofd = 1;
+ if (i < argc) {
+ ofd = open(argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd == -1) {
+ perror("open");
+ exit(1);
+ }
+ }
+
+ if (primary) {
+ /* generate bootblock for primary loader */
+
+ unsigned long bb[64], sum = 0;
+ struct stat st;
+ off_t size;
+ int i;
+
+ if (ofd == 1) {
+ usage();
+ }
+
+ if (fstat(fd, &st) == -1) {
+ perror("fstat");
+ exit(1);
+ }
+
+ size = (st.st_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);
+ memset(bb, 0, sizeof(bb));
+ strcpy((char *) bb, "Linux SRM bootblock");
+ bb[60] = size / BLOCK_SIZE; /* count */
+ bb[61] = 1; /* starting sector # */
+ bb[62] = 0; /* flags---must be 0 */
+ for (i = 0; i < 63; ++i) {
+ sum += bb[i];
+ }
+ bb[63] = sum;
+ if (write(ofd, bb, sizeof(bb)) != sizeof(bb)) {
+ perror("boot-block write");
+ exit(1);
+ }
+ printf("%lu\n", size);
+ return 0;
+ }
+
+ /* read and inspect exec header: */
+
+ if (read(fd, buf, sizeof(buf)) < 0) {
+ perror("read");
+ exit(1);
+ }
+
+#ifdef __ELF__
+ elf = (struct elf64_hdr *) buf;
+
+ if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) == 0) {
+ if (elf->e_type != ET_EXEC) {
+ fprintf(stderr, "%s: %s is not an ELF executable\n",
+ prog_name, inname);
+ exit(1);
+ }
+ if (!aboot_elf_check_arch(elf)) {
+ fprintf(stderr, "%s: is not for this processor (e_machine=%d)\n",
+ prog_name, elf->e_machine);
+ exit(1);
+ }
+ if (elf->e_phnum != 1) {
+ fprintf(stderr,
+ "%s: %d program headers (forgot to link with -N?)\n",
+ prog_name, elf->e_phnum);
+ }
+
+ e_entry = elf->e_entry;
+
+ lseek(fd, elf->e_phoff, SEEK_SET);
+ if (read(fd, buf, sizeof(*elf_phdr)) != sizeof(*elf_phdr)) {
+ perror("read");
+ exit(1);
+ }
+
+ elf_phdr = (struct elf64_phdr *) buf;
+ offset = elf_phdr->p_offset;
+ mem_size = elf_phdr->p_memsz;
+ fil_size = elf_phdr->p_filesz;
+
+ /* work around ELF bug: */
+ if (elf_phdr->p_vaddr < e_entry) {
+ unsigned long delta = e_entry - elf_phdr->p_vaddr;
+ offset += delta;
+ mem_size -= delta;
+ fil_size -= delta;
+ elf_phdr->p_vaddr += delta;
+ }
+
+ if (verbose) {
+ fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
+ prog_name, (long) elf_phdr->p_vaddr,
+ elf_phdr->p_vaddr + fil_size, offset);
+ }
+ }
+#endif
+
+ if (lseek(fd, offset, SEEK_SET) != offset) {
+ perror("lseek");
+ exit(1);
+ }
+
+ if (verbose) {
+ fprintf(stderr, "%s: copying %lu byte from %s\n",
+ prog_name, (unsigned long) fil_size, inname);
+ }
+
+ tocopy = fil_size;
+ while (tocopy > 0) {
+ n = tocopy;
+ if (n > sizeof(buf)) {
+ n = sizeof(buf);
+ }
+ tocopy -= n;
+ if ((size_t) read(fd, buf, n) != n) {
+ perror("read");
+ exit(1);
+ }
+ do {
+ nwritten = write(ofd, buf, n);
+ if ((ssize_t) nwritten == -1) {
+ perror("write");
+ exit(1);
+ }
+ n -= nwritten;
+ } while (n > 0);
+ }
+
+ if (pad) {
+ mem_size = ((mem_size + pad - 1) / pad) * pad;
+ }
+
+ tocopy = mem_size - fil_size;
+ if (tocopy > 0) {
+ fprintf(stderr,
+ "%s: zero-filling bss and aligning to %lu with %lu bytes\n",
+ prog_name, pad, (unsigned long) tocopy);
+
+ memset(buf, 0x00, sizeof(buf));
+ do {
+ n = tocopy;
+ if (n > sizeof(buf)) {
+ n = sizeof(buf);
+ }
+ nwritten = write(ofd, buf, n);
+ if ((ssize_t) nwritten == -1) {
+ perror("write");
+ exit(1);
+ }
+ tocopy -= nwritten;
+ } while (tocopy > 0);
+ }
+ return 0;
+}