From 4024ab566a0d86b7bdb3eeec4aa751ef31a7f883 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini <rubini@gnudd.com> Date: Mon, 8 Apr 2013 16:17:10 +0200 Subject: [PATCH] sdbfs/userspace (and doc): added sdb-extract Signed-off-by: Alessandro Rubini <rubini@gnudd.com> --- sdbfs/doc/sdbfs.in | 42 ++++++++ sdbfs/userspace/.gitignore | 1 + sdbfs/userspace/Makefile | 2 +- sdbfs/userspace/sdb-extract.c | 192 ++++++++++++++++++++++++++++++++++ 4 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 sdbfs/userspace/sdb-extract.c diff --git a/sdbfs/doc/sdbfs.in b/sdbfs/doc/sdbfs.in index 667ffa5..2d9af27 100644 --- a/sdbfs/doc/sdbfs.in +++ b/sdbfs/doc/sdbfs.in @@ -582,6 +582,48 @@ and @i{gensdbfs.c} has been over-allocated as a 64kB area. e38de09fe2bd0dab3ff7ebcab300977e - @end smallexample +@c ========================================================================== +@node sdb-extract +@section sdb-extract + +The @i{sdb-extract} tool is a program that opens an SDBFS file and creates +a directory with the contents of the filesystem and a the associated +configuration file. Running @i{gensdbfs} for this output directory would +create the exact same SDBFS image you started from. + +The tool is meant to help retrieving information from already-built +EEPROM images, and possibly change them before rebuilding an image file. + +The program refuses to change existing directories and extracts the +SDB filesystem to a newly-created directory. It receives two +arguments: the output directory and the input SDB file (i.e., the same +arguments you would pass to @i{gensdbfs}). + +The optional @t{-f} command line option forces @i{sdb-extract} to add +files to an existing directory. In this case the program creates a +configuration file (called @t{--SDB-CONFIG--}) only if it doesn't exist +in the output directory. + +This is an example run of the program, using the @i{doc} directory +of this package as data set: + +@example + % ./gensdbfs ../doc /tmp/doc.sdb + % ./sdb-extract /tmp/doc-extracted /tmp/doc.sdb + % ./gensdbfs /tmp/doc-extracted /tmp/doc2.sdb + % diff -ur ../doc /tmp/doc-extracted/ + Only in /tmp/doc-extracted/: --SDB-CONFIG-- +@end example + +In general, if you re-run @i{gensdbfs} on the extracted directory, the +generated SDBFS image will be different, because the order of the +files is unpredictable. + +Another point to keep in mind is the use of @t{maxsize =} directive +for @i{gensdbfs}. SDB has no concept of ``current'' and ``max'' size, +so a file allocated with @t{maxsize =} will be extracted at its maximum +size, and no @t{maxsize =} is generated in the output @t{--SDB-CONFIG--}. + @c ########################################################################## @node Kernel Support @chapter Kernel Support diff --git a/sdbfs/userspace/.gitignore b/sdbfs/userspace/.gitignore index 74bfd5b..4cfaf59 100644 --- a/sdbfs/userspace/.gitignore +++ b/sdbfs/userspace/.gitignore @@ -1,2 +1,3 @@ gensdbfs sdb-read +sdb-extract diff --git a/sdbfs/userspace/Makefile b/sdbfs/userspace/Makefile index 98e4676..4a367a7 100644 --- a/sdbfs/userspace/Makefile +++ b/sdbfs/userspace/Makefile @@ -13,7 +13,7 @@ CFLAGS = -Wall -ggdb CFLAGS += -I../lib -I../include -I../include/linux LDFLAGS = -L../lib -lsdbfs -PROG = gensdbfs sdb-read +PROG = gensdbfs sdb-read sdb-extract all: $(PROG) diff --git a/sdbfs/userspace/sdb-extract.c b/sdbfs/userspace/sdb-extract.c new file mode 100644 index 0000000..0bb15de --- /dev/null +++ b/sdbfs/userspace/sdb-extract.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2013 CERN (www.cern.ch) + * Author: Alessandro Rubini <rubini@gnudd.com> + * + * Released according to the GNU GPL, version 2 or any later version. + * + * This work is part of the White Rabbit project, a research effort led + * by CERN, the European Institute for Nuclear Research. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> +#include <errno.h> +#include <dirent.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include "libsdbfs.h" +#define CFG_NAME "--SDB-CONFIG--" + +/* + * This is similar to ./sdb-read, so some code duplication is there, + * but I'd better keep the tools separate and simple + */ + +char *prgname; + +static int opt_force, opt_entry; + +static int create_file(struct sdbfs *fs, struct sdb_device *d, FILE *cfgf) +{ + FILE *f; + struct sdb_product *p; + struct sdb_component *c; + char name[32]; + int mode = 0444; + + c = &d->sdb_component; + p = &c->product; + + /* Remove trailing spaces from the name */ + strncpy(name, (char *)p->name, sizeof(p->name)); + name[sizeof(p->name)] = '\0'; + while (name[strlen(name) - 1] == ' ') + name[strlen(name) - 1] = '\0'; + + /* Print cfgfile information */ + fprintf(cfgf, "%s\n" "\tvendor = 0x%016llx\n" "\tdevice = 0x%08x\n", + name, ntohll(p->vendor_id), ntohl(p->device_id)); + fprintf(cfgf, "\tposition = 0x%llx\n", ntohll(c->addr_first)); + if (ntohl(d->bus_specific) & SDB_DATA_WRITE) { + fprintf(cfgf, "\twrite = 1\n"); + mode |= 0222; + } + if (ntohl(d->bus_specific) & SDB_DATA_EXEC) + mode |= 0111; + fprintf(cfgf, "\n"); + + /* Create the actual file unless it is the root directory */ + if (!strcmp(name, ".")) + return 0; + f = fopen(name, "w"); + if (!f) { + fprintf(stderr, "%s: open(%s): %s\n", prgname, name, + strerror(errno)); + return -1; + } + fwrite(fs->data + ntohll(c->addr_first), 1, + ntohll(c->addr_last) + 1 - ntohll(c->addr_first), f); + fclose(f); + chmod(name, mode); + return 0; +} + + +/* As promised, here's the user-interface glue (and initialization, I admit) */ +int main(int argc, char **argv) +{ + int n, new, c, err, cfgfd; + FILE *f, *cfgf; + struct sdbfs _fs; + struct sdbfs *fs = &_fs; /* I like to type "fs->" */ + struct sdb_device *d; + struct stat stbuf; + void *mapaddr; + char *fsname, *dirname; + struct dirent **namelist; + int pagesize = getpagesize(); + + prgname = argv[0]; + + while ( (c = getopt(argc, argv, "e:f")) != -1) { + switch (c) { + case 'f': + opt_force = 1; + break; + case 'e': + if (sscanf(optarg, "%i", &opt_entry) != 1) { + fprintf(stderr, "%s: not a number \"%s\"\n", + prgname, optarg); + exit(1); + } + } + } + if (optind < argc - 2) { + fprintf(stderr, "%s: Use: \"%s [-f] [-e <entry>] " + "<output-dir> <sdb-file>\n", prgname, prgname); + exit(1); + } + fsname = argv[optind + 1]; + dirname = argv[optind]; + + if ( !(f = fopen(fsname, "r")) || fstat(fileno(f), &stbuf) < 0) { + fprintf(stderr, "%s: %s: %s\n", prgname, fsname, + strerror(errno)); + exit(1); + } + + stbuf.st_size += pagesize - 1; + stbuf.st_size &= ~(pagesize - 1); + mapaddr = mmap(0, stbuf.st_size, PROT_READ, MAP_PRIVATE, fileno(f), 0); + if (mapaddr == MAP_FAILED) { + fprintf(stderr, "%s: mmap(%s): %s\n", prgname, fsname, + strerror(errno)); + exit(1); + } + + /* Check output dir is empty, open config file */ + + /* Open the filesystem */ + memset(fs, 0, sizeof(*fs)); + + fs->name = fsname; /* not mandatory */ + fs->blocksize = 256; /* only used for writing, actually */ + fs->entrypoint = opt_entry; + fs->data = mapaddr; + + err = sdbfs_dev_create(fs, 0); + if (err) { + fprintf(stderr, "%s: sdbfs_dev_create(): %s\n", prgname, + strerror(-err)); + fprintf(stderr, "\t(wrong entry point 0x%08lx?)\n", + fs->entrypoint); + exit(1); + } + + /* We are sure the fs is good: create output dir and cfgfile */ + if (mkdir(dirname, 0777) < 0 && errno != EEXIST) { + fprintf(stderr, "%s: %s: %s\n", prgname, dirname, + strerror(errno)); + exit(1); + } + if (chdir(dirname) < 0) { + fprintf(stderr, "%s: %s: %s\n", prgname, dirname, + strerror(errno)); + exit(1); + + } + n = scandir(".", &namelist, 0, 0); + if (!opt_force && n != 2) { + fprintf(stderr, "%s: %s: not empty\n", prgname, dirname); + exit(1); + } + cfgfd = open(CFG_NAME, O_RDWR | O_CREAT | O_EXCL, 0666); + if (cfgfd < 0) { + fprintf(stderr, "%s: Warning: %s/%s: %s\n", prgname, dirname, + CFG_NAME, strerror(errno)); + cfgf = fopen("/dev/null", "w"); + } else { + cfgf = fdopen(cfgfd, "w"); + } + + /* Save the header */ + fprintf(cfgf, "# Configuration file generated by %s, reading %s\n\n", + prgname, fsname); + + /* The root directory is a file like the other ones */ + while ( (d = sdbfs_scan(fs, new)) != NULL) { + create_file(fs, d, cfgf); + new = 0; + } + sdbfs_dev_destroy(fs); + return 0; +} + -- GitLab