Commit 4024ab56 authored by Alessandro Rubini's avatar Alessandro Rubini

sdbfs/userspace (and doc): added sdb-extract

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 36054c91
......@@ -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
......
......@@ -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)
......
/*
* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment