aboutsummaryrefslogtreecommitdiffstats
path: root/roms/SLOF/tools
diff options
context:
space:
mode:
Diffstat (limited to 'roms/SLOF/tools')
-rw-r--r--roms/SLOF/tools/.gitignore2
-rw-r--r--roms/SLOF/tools/Makefile38
-rwxr-xr-xroms/SLOF/tools/create_reloc_table.sh60
-rw-r--r--roms/SLOF/tools/gen_reloc_table.c95
-rw-r--r--roms/SLOF/tools/sloffs.c763
5 files changed, 958 insertions, 0 deletions
diff --git a/roms/SLOF/tools/.gitignore b/roms/SLOF/tools/.gitignore
new file mode 100644
index 000000000..e89174fd6
--- /dev/null
+++ b/roms/SLOF/tools/.gitignore
@@ -0,0 +1,2 @@
+gen_reloc_table
+sloffs
diff --git a/roms/SLOF/tools/Makefile b/roms/SLOF/tools/Makefile
new file mode 100644
index 000000000..6da2e179e
--- /dev/null
+++ b/roms/SLOF/tools/Makefile
@@ -0,0 +1,38 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+include ../make.rules
+
+TARGETS = gen_reloc_table sloffs
+HOSTCFLAGS += -I../romfs/tools
+
+all: $(TARGETS)
+
+crclib.o: ../romfs/tools/crclib.c
+ $(HOSTCC) -W $(HOSTCFLAGS) -c $^ -o $@
+
+%.o: %.c
+ $(HOSTCC) -W $(HOSTCFLAGS) -c $^
+
+gen_reloc_table: gen_reloc_table.o
+ $(HOSTCC) $(HOSTCFLAGS) -o $@ $^
+
+sloffs: sloffs.o crclib.o
+ $(HOSTCC) $(HOSTCFLAGS) -o $@ $^
+
+clean_here:
+ rm -f *.o $(TARGETS)
+
+clean: clean_here
+
+
+distclean: clean_here
diff --git a/roms/SLOF/tools/create_reloc_table.sh b/roms/SLOF/tools/create_reloc_table.sh
new file mode 100755
index 000000000..8cacb742a
--- /dev/null
+++ b/roms/SLOF/tools/create_reloc_table.sh
@@ -0,0 +1,60 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+#!/bin/sh
+
+
+CROSSTMP=`grep ^CROSS $(dirname $0)/../make.rules | cut -d\ -f2`
+
+CROSS=${CROSS-$CROSSTMP}
+
+# Set defaults:
+LD="${CROSS}ld"
+LDFLAGS="-nostdlib"
+LDSFILE=""
+OBJCOPY="${CROSS}objcopy"
+
+DIRNAME=`dirname $0`
+
+# Parse parameters:
+while [ $# -gt 0 ] ; do
+ case "$1" in
+ --ld) LD=$2 ; shift 2 ;;
+ --ldflags) LDFLAGS=$2 ; shift 2 ;;
+ --lds) LDSFILE=$2 ; shift 2 ;;
+ --objcopy) OBJCOPY=$2 ; shift 2 ;;
+ *.o|*.a|-l*|-L*) OBJFILES="$OBJFILES $1" ; shift ;;
+ *) echo "$0:" ; echo " Unsupported argument: $1"; exit -1 ;;
+ esac
+done
+
+if [ -z $LDSFILE ]; then
+ echo "Please specifiy an lds file with the --lds option"
+ exit 42
+fi
+
+TMP1=`mktemp`
+TMP2=`mktemp`
+
+# Now create the two object files:
+$LD $LDFLAGS -T $LDSFILE -o $TMP1.o $OBJFILES || exit -1
+$LD $LDFLAGS -T $LDSFILE -o $TMP2.o $OBJFILES --section-start .text=0x4000000000000000 || exit -1
+
+$OBJCOPY -O binary $TMP1.o $TMP1.bin || exit -1
+$OBJCOPY -O binary $TMP2.o $TMP2.bin || exit -1
+
+# Create the relocation table with gen_reloc_table:
+$DIRNAME/gen_reloc_table $TMP1.bin $TMP2.bin reloc_table.bin
+
+$LD -o reloc_table.o -bbinary reloc_table.bin -e0 || exit -1
+$OBJCOPY --rename-section .data=.reloc reloc_table.o reloc_table.o || exit -1
+
+rm -f $TMP1.o $TMP2.o $TMP1.bin $TMP2.bin reloc_table.bin
diff --git a/roms/SLOF/tools/gen_reloc_table.c b/roms/SLOF/tools/gen_reloc_table.c
new file mode 100644
index 000000000..b15ce9d00
--- /dev/null
+++ b/roms/SLOF/tools/gen_reloc_table.c
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static int reloc_64_cnt;
+
+static int reloc_64[4096];
+
+static void
+output_int(FILE *output_file, int i)
+{
+ fputc((i>>24) & 0xff, output_file);
+ fputc((i>>16) & 0xff, output_file);
+ fputc((i>>8) & 0xff, output_file);
+ fputc(i & 0xff, output_file);
+}
+
+static void
+output_reloc_table(FILE * output_file, int reloc_cnt, int reloc[])
+{
+ int i;
+ for (i=0; i < reloc_cnt; i++)
+ {
+#ifdef DEBUG
+ printf ("reloc %x\n", reloc[i]);
+#endif
+ output_int (output_file, reloc[i]);
+ }
+ if ((reloc_cnt & 1) == 0)
+ output_int (output_file, 0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int cnt_a, cnt_b, offset = -1;
+ unsigned char a, b;
+ FILE *orig, *other, *output_file;
+
+ if (argc != 4)
+ {
+ fprintf (stderr, "reloc_diff orig_file other_file output_file\n");
+ exit(-1);
+ }
+
+ orig = fopen(argv[1], "rb");
+ other = fopen(argv[2], "rb");
+ output_file = fopen(argv[3], "wb");
+ if(orig == NULL || other == NULL || output_file == NULL) {
+ printf("Could not open file.\n");
+ return -1;
+ }
+
+ while (1)
+ {
+ cnt_a = fread(&a, 1, 1, orig);
+ cnt_b = fread(&b, 1, 1, other);
+ offset ++;
+ if (cnt_a != cnt_b)
+ {
+ fprintf (stderr, "Files >%s< and >%s< have not the same length\n",argv[1],argv[2]);
+ exit(-1);
+ }
+
+ if (cnt_a == 0)
+ break;
+
+ if (a == b) continue;
+
+ if (a + 0x40 == b)
+ {
+ reloc_64[reloc_64_cnt++] = offset;
+ }
+ else
+ {
+ fprintf(stderr, "Unknown relocation");
+ fprintf(stderr, "Offset %x: %02x %02x\n", offset, a, b);
+ break;
+ }
+ }
+
+ output_reloc_table(output_file, reloc_64_cnt, reloc_64);
+ return 0;
+}
diff --git a/roms/SLOF/tools/sloffs.c b/roms/SLOF/tools/sloffs.c
new file mode 100644
index 000000000..264b0eabc
--- /dev/null
+++ b/roms/SLOF/tools/sloffs.c
@@ -0,0 +1,763 @@
+/******************************************************************************
+ * Copyright (c) 2008, 2009 Adrian Reber
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * Adrian Reber - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include <time.h>
+#include <errno.h>
+
+#include <calculatecrc.h>
+#include <crclib.h>
+
+#define VERSION 1
+
+#ifdef _BIG_ENDIAN
+#define cpu_to_be64(x) (x)
+#define be64_to_cpu(x) (x)
+#define be16_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
+#else
+#define cpu_to_be64(x) bswap_64(x)
+#define be64_to_cpu(x) bswap_64(x)
+#define be16_to_cpu(x) bswap_16(x)
+#define be32_to_cpu(x) bswap_32(x)
+#endif
+
+
+/* no board dependencies wanted here, let's hardcode SLOF's
+ * magic strings here */
+
+#define FLASHFS_MAGIC "magic123"
+#define FLASHFS_PLATFORM_MAGIC "JS2XBlade"
+#define FLASHFS_PLATFORM_REVISION "1"
+
+/* there seems to be no structure defined anywhere in the code
+ * which resembles the actual sloffs/romfs file header;
+ * so defining it here for now */
+
+struct sloffs {
+ uint64_t next;
+ uint64_t len;
+ uint64_t flags;
+ uint64_t data;
+ char *name;
+};
+
+/* sloffs metadata size:
+ * 4 * 8: 4 * uint64_t + (filename length) */
+#define SLOFFS_META (4 * 8)
+#define ALIGN64(x) (((x) + 7) & ~7)
+
+static struct sloffs *
+next_file_mm(struct sloffs *sloffs)
+{
+ return (struct sloffs *)((unsigned char *)sloffs +
+ be64_to_cpu(sloffs->next));
+}
+
+static int
+next_file(const int fd, struct sloffs *sloffs)
+{
+ int ret;
+ uint64_t size;
+ uint64_t offset;
+ char *name;
+
+ offset = 0;
+
+ /* if sloffs is not all NULL we want the next file
+ * else we just take the first file */
+ if (sloffs->name && sloffs->len && sloffs->data) {
+ offset = be64_to_cpu(sloffs->next);
+ /* we already read over the header; skip it in the seek */
+ offset -= be64_to_cpu(sloffs->data);
+ free(sloffs->name);
+ sloffs->name = NULL;
+ lseek(fd, offset, SEEK_CUR);
+ } else {
+ lseek(fd, offset, SEEK_SET);
+ }
+
+ ret = read(fd, sloffs, SLOFFS_META);
+ if (ret == -1)
+ return -1;
+ /* read the size of the header */
+ size = be64_to_cpu(sloffs->data);
+ /* get the size of the filename */
+ size -= SLOFFS_META;
+ name = malloc(size);
+
+ ret = read(fd, name, size);
+ if (ret == -1) {
+ free(name);
+ return -1;
+ }
+ sloffs->name = name;
+ return 0;
+}
+
+static struct sloffs *
+find_file_mm(const void *data, const char *name)
+{
+ struct sloffs *sloffs = (struct sloffs *)data;
+
+ for (;;) {
+ if (!strcmp((char *)&sloffs->name, name))
+ return sloffs;
+
+ if (be64_to_cpu(sloffs->next) == 0)
+ break;
+ sloffs = next_file_mm(sloffs);
+ }
+ return NULL;
+}
+
+static struct sloffs *
+find_file(const int fd, const char *name, struct sloffs *sloffs)
+{
+ memset(sloffs, 0, sizeof(struct sloffs));
+
+ if (next_file(fd, sloffs))
+ return NULL;
+
+ for (;;) {
+ if (!strcmp(sloffs->name, name))
+ return sloffs;
+
+ if (be64_to_cpu(sloffs->next) == 0)
+ break;
+ if (next_file(fd, sloffs))
+ return NULL;
+ }
+
+ free(sloffs->name);
+ return NULL;
+}
+
+static struct stH *
+sloffs_header_mm(const void *data)
+{
+ struct sloffs *sloffs;
+ struct stH *header;
+
+ /* find the "header" file with all the information about
+ * the flash image */
+ sloffs = find_file_mm(data, "header");
+ if (!sloffs) {
+ printf("sloffs file \"header\" not found. aborting...\n");
+ return NULL;
+ }
+
+ header = (struct stH *)((unsigned char *)sloffs +
+ be64_to_cpu(sloffs->data));
+ return header;
+}
+
+static struct stH *
+sloffs_header(const int fd)
+{
+ struct sloffs file;
+ struct sloffs *sloffs;
+ struct stH *header;
+ ssize_t rc;
+
+ header = (struct stH *)malloc(sizeof(struct stH));
+
+ /* find the "header" file with all the information about
+ * the flash image */
+ sloffs = find_file(fd, "header", &file);
+ if (!sloffs) {
+ printf("sloffs file \"header\" not found. aborting...\n");
+ return NULL;
+ }
+
+ rc = read(fd, header, sizeof(struct stH));
+ if (rc != sizeof(struct stH)) {
+ printf("Reading header, rc %ld, errno %d\n", rc, errno);
+ free(header);
+ header = NULL;
+ }
+ free(sloffs->name);
+ return header;
+}
+
+static uint64_t
+header_length_mm(const void *data)
+{
+ struct sloffs *sloffs;
+
+ /* find the "header" file with all the information about
+ * the flash image */
+ sloffs = find_file_mm(data, "header");
+ if (!sloffs) {
+ printf("sloffs file \"header\" not found. aborting...\n");
+ return 0;
+ }
+ return be64_to_cpu(sloffs->len);
+}
+
+static uint64_t
+header_length(const int fd)
+{
+ struct sloffs file;
+ struct sloffs *sloffs;
+
+ /* find the "header" file with all the information about
+ * the flash image */
+ sloffs = find_file(fd, "header", &file);
+ if (!sloffs) {
+ printf("sloffs file \"header\" not found. aborting...\n");
+ return 0;
+ }
+
+ free(sloffs->name);
+ return be64_to_cpu(sloffs->len);
+}
+
+static void
+update_modification_time(struct stH *header)
+{
+ struct tm *tm;
+ time_t caltime;
+ char dastr[16] = { 0, };
+ uint64_t date;
+
+ /* update modification date
+ * copied from create_crc.c */
+ caltime = time(NULL);
+ tm = localtime(&caltime);
+ strftime(dastr, 15, "0x%Y%m%d%H%M", tm);
+ date = cpu_to_be64(strtoll(dastr, NULL, 16));
+
+ /* this does not match the definition from
+ * struct stH, but we immitate the bug from
+ * flash image creation in create_crc.c.
+ * The date is in mdate and time in padding2. */
+ memcpy(&(header->mdate), &date, 8);
+}
+
+static void
+update_crc(void *data)
+{
+ uint64_t crc;
+ struct stH *header = sloffs_header_mm(data);
+ uint64_t len = be64_to_cpu(header->flashlen);
+
+ /* calculate header CRC */
+ header->ui64CRC = 0;
+ crc = checkCRC(data, header_length_mm(data), 0);
+ header->ui64CRC = cpu_to_be64(crc);
+ /* calculate flash image CRC */
+ crc = checkCRC(data, len, 0);
+ *(uint64_t *)(data + len - 8) = cpu_to_be64(crc);
+}
+
+static uint64_t
+check_image_crc(const int fd, uint64_t len)
+{
+ uint64_t crc;
+ uint64_t i;
+ uint64_t read_bytes;
+ unsigned char buffer[4096];
+
+ lseek(fd, 0, SEEK_SET);
+ crc = 0;
+ read_bytes = 0;
+ while (read_bytes < len) {
+ i = read(fd, buffer, 4096);
+ read_bytes += i;
+ if (read_bytes > len)
+ i -= read_bytes - len;
+ crc = calCRCword(buffer, i, crc);
+ }
+ return crc;
+}
+static void
+sloffs_append(const int file, const char *name, const char *dest)
+{
+ void *append;
+ unsigned char *write_data;
+ void *write_start;
+ int fd;
+ int out;
+ struct stat stat;
+ struct stH *header;
+ uint64_t new_len;
+ struct sloffs *sloffs;
+ struct sloffs new_file;
+ uint64_t read_len;
+ int i;
+ ssize_t rc;
+
+ fd = open(name, O_RDONLY);
+
+ if (fd == -1) {
+ perror(name);
+ exit(1);
+ }
+
+ fstat(fd, &stat);
+ append = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ header = sloffs_header(file);
+
+ if (!header)
+ return;
+
+ new_len = ALIGN64(stat.st_size) + be64_to_cpu(header->flashlen);
+ /* add the length of the sloffs file meta information */
+ new_len += SLOFFS_META;
+ /* add the length of the filename */
+ new_len += ALIGN64(strlen(name) + 1);
+
+ out = open(dest, O_CREAT | O_RDWR | O_TRUNC, 00666);
+
+ if (out == -1) {
+ perror(dest);
+ exit(1);
+ }
+
+ /* write byte at the end to be able to mmap it */
+ lseek(out, new_len - 1, SEEK_SET);
+ rc = write(out, "", 1);
+ if (rc != 1) {
+ printf("Extending file failed, rc %ld, errno %d\n", rc, errno);
+ exit(1);
+ }
+ write_start = mmap(NULL, new_len, PROT_READ | PROT_WRITE,
+ MAP_SHARED, out, 0);
+
+ memset(write_start, 0, new_len);
+ memset(&new_file, 0, sizeof(struct sloffs));
+
+ new_file.len = cpu_to_be64(stat.st_size);
+ new_file.data = cpu_to_be64(SLOFFS_META + ALIGN64(strlen(name) + 1));
+
+ if (write_start == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+
+ lseek(file, 0, SEEK_SET);
+ write_data = write_start;
+ read_len = be64_to_cpu(header->flashlen);
+ for (;;) {
+ i = read(file, write_data, read_len);
+ if (i < 0) {
+ perror("read");
+ exit(1);
+ }
+ if (i == 0)
+ break;
+ write_data += i;
+ read_len -= i;
+ }
+ /* -8: overwrite old CRC */
+ write_data = write_start + be64_to_cpu(header->flashlen) - 8;
+ memcpy(write_data, &new_file, SLOFFS_META);
+ write_data += SLOFFS_META;
+ /* write the filename */
+ memcpy(write_data, name, strlen(name));
+ write_data += ALIGN64(strlen(name) + 1 );
+ memcpy(write_data, append, stat.st_size);
+
+ write_data = write_start;
+
+ /* find last file */
+ sloffs = (struct sloffs *)write_start;
+ for (;;) {
+ if (be64_to_cpu(sloffs->next) == 0)
+ break;
+ sloffs = next_file_mm(sloffs);
+ }
+ /* get the distance to the next file */
+ sloffs->next = ALIGN64(be64_to_cpu(sloffs->len));
+ /* and the offset were the data starts */
+ sloffs->next += be64_to_cpu(sloffs->data);
+ /* and we have to skip the end of file marker
+ * if one is there; if the last uint64_t is -1
+ * it is an end of file marker; this is a bit dangerous
+ * but there is no other way to detect the end of
+ * file marker */
+ if ((uint64_t)be64_to_cpu(*(uint64_t *)((unsigned char *)sloffs +
+ sloffs->next)) == (uint64_t)-1ULL)
+ sloffs->next += 8;
+
+ sloffs->next = cpu_to_be64(sloffs->next);
+
+ free(header);
+ /* update new length of flash image */
+ header = sloffs_header_mm(write_start);
+ header->flashlen = cpu_to_be64(new_len);
+
+ update_modification_time(header);
+
+ update_crc(write_start);
+
+ munmap(append, stat.st_size);
+ munmap(write_start, new_len);
+ close(fd);
+ close(out);
+}
+
+static void print_header_date(void *dptr)
+{
+ uint8_t *date = dptr;
+
+ if (date[2] || date[3] || date[4] || date[5] || date[6] || date[7]) {
+ printf("%02x%02x-%02x-%02x %02x:%02x", date[2], date[3],
+ date[4], date[5], date[6], date[7]);
+ } else {
+ printf("N/A");
+ }
+
+}
+
+static void
+sloffs_dump(const int fd)
+{
+ void *data;
+ struct stH *header;
+ struct sloffs file;
+ int i;
+ uint64_t crc;
+ uint64_t header_len;
+ ssize_t rc;
+
+ header = sloffs_header(fd);
+
+ if (!header)
+ return;
+
+ if (memcmp(FLASHFS_MAGIC, header->magic, strlen(FLASHFS_MAGIC))) {
+ printf("sloffs magic not found. "
+ "probably not a valid SLOF flash image. aborting...\n");
+ return;
+ }
+ printf(" Magic : %s\n", header->magic);
+ printf(" Platform : %s\n", header->platform_name);
+ printf(" Version : %s\n", header->version);
+ /* there is a bug in the date position;
+ * it should be at header->date, but it is at (header->date + 2) */
+ printf(" Build Date : ");
+ print_header_date(header->date);
+ printf("\n");
+ printf(" Modify Date : ");
+ print_header_date(header->mdate);
+ printf("\n");
+ printf(" Image Length: %ld", be64_to_cpu(header->flashlen));
+ printf(" (0x%lx) bytes\n", be64_to_cpu(header->flashlen));
+ printf(" Revision : %s\n", header->platform_revision);
+ crc = be64_to_cpu(header->ui64CRC);
+ printf(" Header CRC : 0x%016lx CRC check: ", crc);
+ /* to test the CRC of the header we need to know the actual
+ * size of the file and not just the size of the data
+ * which could be easily obtained with sizeof(struct stH);
+ * the actual size can only be obtained from the filesystem
+ * meta information */
+ header_len = header_length(fd);
+ /* no copy the header to memory to crc test it */
+ data = malloc(header_len);
+ lseek(fd, 0, SEEK_SET);
+ rc = read(fd, data, header_len);
+ if (rc != (ssize_t) header_len) {
+ printf("Reading header failed, rc %zd, errno %d\n", rc, errno);
+ return;
+ }
+ crc = calCRCword((unsigned char *)data, header_length(fd), 0);
+ free(data);
+ if (!crc)
+ printf("[OK]");
+ else
+ printf("[FAILED]");
+ printf("\n");
+
+ crc = be64_to_cpu(header->flashlen);
+ /* move to the CRC */
+ lseek(fd, crc - 8, SEEK_SET);
+ /* read it */
+ rc = read(fd, &crc, 8);
+ if (rc != 8) {
+ printf("Reading crc failed, rc %zd, errno %d\n", rc, errno);
+ return;
+ }
+ crc = be64_to_cpu(crc);
+ printf(" Image CRC : 0x%016lx CRC check: ", crc);
+ crc = check_image_crc(fd, be64_to_cpu(header->flashlen));
+ if (!crc)
+ printf("[OK]");
+ else
+ printf("[FAILED]");
+ printf("\n");
+
+ /* count number of files */
+ i = 0;
+ memset(&file, 0, sizeof(struct sloffs));
+ if (next_file(fd, &file))
+ return;
+ for (;;) {
+ i++;
+
+ if (be64_to_cpu(file.next) == 0)
+ break;
+ if (next_file(fd, &file))
+ return;
+ }
+ free(file.name);
+ printf(" Files : %d\n", i);
+ free(header);
+}
+
+static void
+sloffs_list(const int fd)
+{
+ const char *name_header = "File Name";
+ unsigned int i;
+ unsigned int max;
+ unsigned int line;
+ struct sloffs file;
+ uint64_t offset = 0;
+
+ memset(&file, 0, sizeof(struct sloffs));
+
+ if (next_file(fd, &file))
+ return;
+
+ /* find largest name */
+ max = strlen(name_header);
+ for (;;) {
+ if (max < strlen((char *)file.name))
+ max = strlen((char *)file.name);
+
+ if (be64_to_cpu(file.next) == 0)
+ break;
+ if (next_file(fd, &file))
+ return;
+ }
+
+ free(file.name);
+
+
+ /* have at least two spaces between name and size column */
+ max += 2;
+
+ /* header for listing */
+ line = printf(" Offset ");
+ line += printf("%s", name_header);
+ for (i = 0; i < max - strlen(name_header); i++)
+ line += printf(" ");
+ line += printf("Size ");
+ line += printf("Flags\n");
+ printf(" ");
+ for (i = 0; i <= line; i++)
+ printf("=");
+ printf("\n");
+
+ memset(&file, 0, sizeof(struct sloffs));
+
+ if (next_file(fd, &file))
+ return;
+
+ for (;;) {
+ printf(" 0x%08lx", offset);
+ offset += be64_to_cpu(file.next);
+ printf(" %s", file.name);
+ for (i = 0; i < max - strlen(file.name); i++)
+ printf(" ");
+
+ printf("%07ld ", be64_to_cpu(file.len));
+ printf("(0x%06lx)", be64_to_cpu(file.len));
+ printf(" 0x%08lx\n", be64_to_cpu(file.flags));
+
+ if (be64_to_cpu(file.next) == 0)
+ break;
+ if (next_file(fd, &file))
+ return;
+ }
+ free(file.name);
+}
+
+static void
+sloffs_copy(const int file, const char *name)
+{
+ uint64_t len;
+ int out;
+ unsigned char *write_buf;
+ int i;
+ struct stH *header;
+ ssize_t rc;
+
+ header = sloffs_header(file);
+
+ if (!header)
+ return;
+
+ len = be64_to_cpu(header->flashlen);
+ free(header);
+
+ out = open(name, O_CREAT | O_RDWR | O_TRUNC, 00666);
+
+ if (out == -1) {
+ perror(name);
+ exit(1);
+ }
+ /* write byte at the end to be able to mmap it */
+ lseek(out, len - 1, SEEK_SET);
+ rc = write(out, "", 1);
+ if (rc != 1) {
+ printf("Extending file failed, rc %zd, errno %d\n", rc, errno);
+ exit(1);
+ }
+ write_buf = mmap(NULL, len, PROT_WRITE, MAP_SHARED, out, 0);
+
+ if (write_buf == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+
+ lseek(file, 0, SEEK_SET);
+
+ for (;;) {
+ i = read(file, write_buf, len);
+ if (i < 0) {
+ perror("read");
+ exit(1);
+ }
+ if (i == 0)
+ break;
+ write_buf += i;
+ len -= i;
+ }
+
+ munmap(write_buf, len);
+ close(out);
+}
+
+static void
+usage(void)
+{
+ printf("sloffs lists or changes a SLOF flash image\n\n");
+ printf("Usage:\n");
+ printf(" sloffs [OPTION]... [FILE]\n\n");
+ printf("Options:\n");
+ printf(" -h, --help show this help, then exit\n");
+ printf(" -l, --list list all files in the flash image\n");
+ printf(" -v, --version print the version, then exit\n");
+ printf(" -d, --dump dump the information from the header\n");
+ printf(" -a, --append=FILENAME append file at the end of\n");
+ printf(" the existing image\n");
+ printf(" -o, --output=FILENAME if appending a file this parameter\n");
+ printf(" is necessary to specify the name of\n");
+ printf(" the output file\n");
+ printf(" -c, --copy=FILENAME copy SLOF image to specified file\n");
+ printf(" this is especially useful if the\n");
+ printf(" source file is /dev/slof_flash\n");
+ printf("\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int fd;
+ const struct option loption[] = {
+ { "help", 0, NULL, 'h' },
+ { "list", 0, NULL, 'l' },
+ { "version", 0, NULL, 'v' },
+ { "dump", 0, NULL, 'd' },
+ { "append", 1, NULL, 'a' },
+ { "output", 1, NULL, 'o' },
+ { "copy", 1, NULL, 'o' },
+ { 0, 0, 0, 0 }
+ };
+ const char *soption = "dhlva:o:c:";
+ int c;
+ char mode = 0;
+ char *append = NULL;
+ char *output = NULL;
+
+ for (;;) {
+ c = getopt_long(argc, argv, soption, loption, NULL);
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'l':
+ mode = 'l';
+ break;
+ case 'v':
+ printf("sloffs (version %d)\n", VERSION);
+ exit(0);
+ case 'd':
+ mode = 'd';
+ break;
+ case 'a':
+ mode = 'a';
+ append = strdup(optarg);
+ break;
+ case 'o':
+ output = strdup(optarg);
+ break;
+ case 'c':
+ mode = 'c';
+ output = strdup(optarg);
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+
+ if (optind >= argc)
+ usage();
+
+ fd = open(argv[optind], O_RDONLY);
+
+ if (fd == -1) {
+ perror(argv[optind]);
+ exit(1);
+ }
+
+ lseek(fd, 0, SEEK_SET);
+
+ switch (mode) {
+ case 'l':
+ sloffs_list(fd);
+ break;
+ case 'd':
+ sloffs_dump(fd);
+ break;
+ case 'a':
+ if (!output) {
+ printf("sloffs requires -o, --output=FILENAME"
+ " when in append mode\n\n");
+ usage();
+ }
+ sloffs_append(fd, append, output);
+ break;
+ case 'c':
+ sloffs_copy(fd, output);
+ break;
+ }
+
+ free(append);
+ free(output);
+ close(fd);
+ return 0;
+}