mirror of
https://github.com/pengutronix/genimage.git
synced 2024-11-23 01:34:12 +08:00
initial import
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
commit
7e5122f621
14
Makefile
Normal file
14
Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
CFLAGS=-Wall
|
||||
LDFLAGS=-lconfuse
|
||||
all: genimage
|
||||
DEPS = genimage.h list.h
|
||||
|
||||
%.o: %.c $(DEPS)
|
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
genimage: genimage.o image-jffs2.o image-ext2.o image-ubi.o image-ubifs.o \
|
||||
image-flash.o image-file.o image-tar.o image-hd.o util.o config.o
|
||||
|
||||
clean:
|
||||
rm -f *.o genimage
|
194
config.c
Normal file
194
config.c
Normal file
@ -0,0 +1,194 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
static LIST_HEAD(optlist);
|
||||
|
||||
struct config {
|
||||
const char *name;
|
||||
cfg_opt_t opt;
|
||||
const char *env;
|
||||
char cmdlineopt;
|
||||
struct list_head list;
|
||||
char *value;
|
||||
char *def;
|
||||
};
|
||||
|
||||
const char *get_opt(const char *name)
|
||||
{
|
||||
struct config *c;
|
||||
|
||||
list_for_each_entry(c, &optlist, list) {
|
||||
if (!strcmp(c->name, name))
|
||||
return c->value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int add_opt(const char *name, char cmdline, const char *env, cfg_opt_t *opt, char *def)
|
||||
{
|
||||
struct config *c = xzalloc(sizeof(*c));
|
||||
|
||||
c->name = strdup(name);
|
||||
c->cmdlineopt = cmdline;
|
||||
c->env = env;
|
||||
c->def = def;
|
||||
memcpy(&c->opt, opt, sizeof(cfg_opt_t));
|
||||
|
||||
list_add_tail(&c->list, &optlist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cfg_opt_t *get_config_opts(void)
|
||||
{
|
||||
struct config *c;
|
||||
int num_opts = 0;;
|
||||
cfg_opt_t *opts;
|
||||
int i = 0;
|
||||
cfg_opt_t cfg_end[] = {
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
list_for_each_entry(c, &optlist, list)
|
||||
num_opts++;
|
||||
|
||||
opts = xzalloc(sizeof(cfg_opt_t) * (num_opts + 1));
|
||||
|
||||
list_for_each_entry(c, &optlist, list) {
|
||||
memcpy(&opts[i], &c->opt, sizeof(cfg_opt_t));
|
||||
i++;
|
||||
}
|
||||
|
||||
memcpy(&opts[i], cfg_end, sizeof(cfg_opt_t));
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
int set_config_opts(int argc, char *argv[], cfg_t *cfg)
|
||||
{
|
||||
struct config *c;
|
||||
cfg_t *cfgsec;
|
||||
|
||||
list_for_each_entry(c, &optlist, list) {
|
||||
char *str = c->def;
|
||||
if (str)
|
||||
c->value = strdup(str);
|
||||
}
|
||||
|
||||
list_for_each_entry(c, &optlist, list) {
|
||||
char *str = getenv(c->env);
|
||||
if (str) {
|
||||
if (c->value)
|
||||
free(c->value);
|
||||
c->value = strdup(str);
|
||||
}
|
||||
}
|
||||
|
||||
cfgsec = cfg_getsec(cfg, "config");
|
||||
if (cfgsec) {
|
||||
list_for_each_entry(c, &optlist, list) {
|
||||
char *str = cfg_getstr(cfgsec, c->opt.name);
|
||||
if (str) {
|
||||
if (c->value)
|
||||
free(c->value);
|
||||
c->value = strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *imagepath(void)
|
||||
{
|
||||
return get_opt("outputpath");
|
||||
}
|
||||
|
||||
const char *inputpath(void)
|
||||
{
|
||||
return get_opt("inputpath");
|
||||
}
|
||||
|
||||
const char *rootpath(void)
|
||||
{
|
||||
return get_opt("rootpath");
|
||||
}
|
||||
|
||||
const char *tmppath(void)
|
||||
{
|
||||
return get_opt("tmppath");
|
||||
}
|
||||
|
||||
static struct config opts[] = {
|
||||
{
|
||||
.name = "rootpath",
|
||||
.opt = CFG_STR("rootpath", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 'r',
|
||||
.env = "PTXMKIMAGE_ROOTPATH",
|
||||
}, {
|
||||
.name = "tmppath",
|
||||
.opt = CFG_STR("tmppath", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 't',
|
||||
.env = "PTXMKIMAGE_TMPPATH",
|
||||
}, {
|
||||
.name = "inputpath",
|
||||
.opt = CFG_STR("inputpath", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 'i',
|
||||
.env = "PTXMKIMAGE_INPUTPATH",
|
||||
}, {
|
||||
.name = "outputpath",
|
||||
.opt = CFG_STR("outputpath", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 'o',
|
||||
.env = "PTXMKIMAGE_OUTPUTPATH",
|
||||
}, {
|
||||
.name = "mkfsubifs",
|
||||
.opt = CFG_STR("mkfsubifs", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 'o',
|
||||
.env = "PTXMKIMAGE_MKFSUBIFS",
|
||||
.def = "mkfs.ubifs",
|
||||
}, {
|
||||
.name = "mkfsjffs2",
|
||||
.opt = CFG_STR("mkfsjffs2", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 'o',
|
||||
.env = "PTXMKIMAGE_MKFJFFS2",
|
||||
.def = "mkfs.jffs2",
|
||||
}, {
|
||||
.name = "ubinize",
|
||||
.opt = CFG_STR("ubinize", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 'o',
|
||||
.env = "PTXMKIMAGE_UBINIZE",
|
||||
.def = "ubinize",
|
||||
}, {
|
||||
.name = "genext2fs",
|
||||
.opt = CFG_STR("genext2fs", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 'o',
|
||||
.env = "PTXMKIMAGE_GENEXT2FS",
|
||||
.def = "genext2fs",
|
||||
}, {
|
||||
.name = "tar",
|
||||
.opt = CFG_STR("tar", NULL, CFGF_NONE),
|
||||
.cmdlineopt = 'o',
|
||||
.env = "PTXMKIMAGE_TAR",
|
||||
.def = "tar",
|
||||
},
|
||||
};
|
||||
|
||||
int init_config(void)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(opts); i++) {
|
||||
ret = add_opt(opts[i].name, opts[i].cmdlineopt, opts[i].env, &opts[i].opt, opts[i].def);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
18
flash.conf
Normal file
18
flash.conf
Normal file
@ -0,0 +1,18 @@
|
||||
flash nand-64M-512 {
|
||||
pebsize = 16384
|
||||
lebsize = 15360
|
||||
numpebs = 4096
|
||||
minimum-io-unit-size = 512
|
||||
vid-header-offset = 512
|
||||
sub-page-size = 512
|
||||
}
|
||||
|
||||
flash nor-64M-128k {
|
||||
pebsize = 131072
|
||||
lebsize = 130944
|
||||
numpebs = 256
|
||||
minimum-io-unit-size = 1
|
||||
vid-header-offset = 64
|
||||
sub-page-size = 1
|
||||
}
|
||||
|
500
genimage.c
Normal file
500
genimage.c
Normal file
@ -0,0 +1,500 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <confuse.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
*
|
||||
* - add documentation
|
||||
* - implement extraargs for the different image handlers (i.e. jffs2-extraargs = "", genext2fs-extraargs = "")
|
||||
* - make more configurable (path to programs and the like)
|
||||
* - implement missing image types (cpio, iso)
|
||||
* - free memory after usage
|
||||
* - make more failsafe (does flashtype exist where necessary)
|
||||
* - check for recursive image references
|
||||
* - implement command line switches (--verbose, --dry-run, --config=)
|
||||
* - implement a log(struct image *, const char *format, ...) function
|
||||
* - implement different compression types for tar (depending on file suffix or explicit switches)
|
||||
*
|
||||
*/
|
||||
static struct image_handler *handlers[] = {
|
||||
&jffs2_handler,
|
||||
&flash_handler,
|
||||
&tar_handler,
|
||||
&ubi_handler,
|
||||
&ubifs_handler,
|
||||
&hdimage_handler,
|
||||
&ext2_handler,
|
||||
&file_handler,
|
||||
};
|
||||
|
||||
static int image_get_type(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
int num = 0, i, x;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
|
||||
struct image_handler *handler = handlers[i];
|
||||
|
||||
x = cfg_size(cfg, handler->type);
|
||||
if (x)
|
||||
image->handler = handler;
|
||||
num += x;
|
||||
}
|
||||
|
||||
if (num > 1) {
|
||||
fprintf(stderr, "multiple image types given\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (num < 1) {
|
||||
fprintf(stderr, "no image type given\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
image->imagesec = cfg_getsec(cfg, image->handler->type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void dump_image(struct image *i)
|
||||
{
|
||||
printf("file: %-25s "
|
||||
"name: %-20s "
|
||||
"size: %-10lld "
|
||||
"offset: %-10lld "
|
||||
"mountpoint: %-20s "
|
||||
"partition_type: %-3d\n", i->file, i->name, i->size, i->offset,
|
||||
i->mountpoint, i->partition_type);
|
||||
i->handler->handler(i);
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long long cfg_getint_suffix(cfg_t *sec, const char *name)
|
||||
{
|
||||
const char *str = cfg_getstr(sec, name);
|
||||
unsigned long long val = 0;
|
||||
|
||||
if (str)
|
||||
val = strtoul_suffix(str, NULL, 0);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static cfg_opt_t partition_opts[] = {
|
||||
CFG_STR("offset", NULL, CFGF_NONE),
|
||||
CFG_STR("size", NULL, CFGF_NONE),
|
||||
CFG_INT("partition-type", 0, CFGF_NONE),
|
||||
CFG_STR("image", NULL, CFGF_NONE),
|
||||
CFG_BOOL("autoresize", 0, CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
static cfg_opt_t image_common_opts[] = {
|
||||
CFG_STR("name", NULL, CFGF_NONE),
|
||||
CFG_STR("size", NULL, CFGF_NONE),
|
||||
CFG_STR("mountpoint", NULL, CFGF_NONE),
|
||||
CFG_STR("offset", NULL, CFGF_NONE),
|
||||
CFG_STR("flashtype", NULL, CFGF_NONE),
|
||||
CFG_SEC("partition", partition_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
};
|
||||
|
||||
static cfg_opt_t flashchip_opts[] = {
|
||||
CFG_STR("pebsize", "", CFGF_NONE),
|
||||
CFG_STR("lebsize", "", CFGF_NONE),
|
||||
CFG_STR("numpebs", "", CFGF_NONE),
|
||||
CFG_STR("minimum-io-unit-size", "", CFGF_NONE),
|
||||
CFG_STR("vid-header-offset", "", CFGF_NONE),
|
||||
CFG_STR("sub-page-size", "", CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
static LIST_HEAD(images);
|
||||
|
||||
struct image *image_get(const char *filename)
|
||||
{
|
||||
struct image *image;
|
||||
|
||||
list_for_each_entry(image, &images, list) {
|
||||
if (!strcmp(image->file, filename))
|
||||
return image;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int image_generate(struct image *image)
|
||||
{
|
||||
int ret;
|
||||
struct partition *part;
|
||||
|
||||
if (image->done)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(part, &image->partitions, list) {
|
||||
struct image *child;
|
||||
child = image_get(part->image);
|
||||
if (!child) {
|
||||
image_error(image, "could not find %s\n", part->image);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = image_generate(child);
|
||||
if (ret) {
|
||||
image_error(image, "could not generate %s\n", child->file);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (image->handler->generate) {
|
||||
ret = image->handler->generate(image);
|
||||
} else {
|
||||
error("no generate function for %s\n", image->file);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
image->done = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *mountpath(struct image *image)
|
||||
{
|
||||
return image->mp->mountpath;
|
||||
}
|
||||
|
||||
static LIST_HEAD(flashlist);
|
||||
|
||||
int parse_flashes(cfg_t *cfg)
|
||||
{
|
||||
int num_flashes;
|
||||
int i;
|
||||
|
||||
num_flashes = cfg_size(cfg, "flash");
|
||||
|
||||
for (i = 0; i < num_flashes; i++) {
|
||||
cfg_t *flashsec = cfg_getnsec(cfg, "flash", i);
|
||||
struct flash_type *flash = xzalloc(sizeof *flash);
|
||||
|
||||
flash->name = cfg_title(flashsec);
|
||||
flash->pebsize = cfg_getint_suffix(flashsec, "pebsize");
|
||||
flash->lebsize = cfg_getint_suffix(flashsec, "lebsize");
|
||||
flash->numpebs = cfg_getint_suffix(flashsec, "numpebs");
|
||||
flash->minimum_io_unit_size = cfg_getint_suffix(flashsec, "minimum-io-unit-size");
|
||||
flash->vid_header_offset = cfg_getint_suffix(flashsec, "vid-header-offset");
|
||||
flash->sub_page_size = cfg_getint_suffix(flashsec, "sub-page-size");
|
||||
list_add_tail(&flash->list, &flashlist);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct flash_type *flash_type_get(const char *name)
|
||||
{
|
||||
struct flash_type *flash;
|
||||
|
||||
list_for_each_entry(flash, &flashlist, list) {
|
||||
if (!strcmp(flash->name, name))
|
||||
return flash;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int image_set_flash_type(struct image *image, struct flash_type *type)
|
||||
{
|
||||
if (!image->flash_type) {
|
||||
image->flash_type = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (image->flash_type != type)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_partitions(struct image *image, cfg_t *imagesec)
|
||||
{
|
||||
struct partition *part;
|
||||
int num_partitions;
|
||||
int i;
|
||||
|
||||
num_partitions = cfg_size(imagesec, "partition");
|
||||
|
||||
for (i = 0; i < num_partitions; i++) {
|
||||
cfg_t *partsec = cfg_getnsec(imagesec, "partition", i);
|
||||
|
||||
part = xzalloc(sizeof *part);
|
||||
part->name = cfg_title(partsec);
|
||||
list_add_tail(&part->list, &image->partitions);
|
||||
part->size = cfg_getint_suffix(partsec, "size");
|
||||
part->offset = cfg_getint_suffix(partsec, "offset");
|
||||
part->partition_type = cfg_getint(partsec, "partition-type");
|
||||
part->image = cfg_getstr(partsec, "image");
|
||||
part->autoresize = cfg_getbool(partsec, "autoresize");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_flash_type(void)
|
||||
{
|
||||
struct image *image;
|
||||
|
||||
list_for_each_entry(image, &images, list) {
|
||||
struct partition *part;
|
||||
if (!image->flash_type)
|
||||
continue;
|
||||
list_for_each_entry(part, &image->partitions, list) {
|
||||
struct image *i;
|
||||
i = image_get(part->image);
|
||||
if (!i)
|
||||
return -EINVAL;
|
||||
if (i->flash_type) {
|
||||
if (i->flash_type != image->flash_type) {
|
||||
printf("conflicting flash types: %s has flashtype %s whereas %s has flashtype %s\n",
|
||||
i->file, i->flash_type->name, image->file, image->flash_type->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
i->flash_type = image->flash_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static LIST_HEAD(mountpoints);
|
||||
|
||||
static struct mountpoint *add_mountpoint(const char *path)
|
||||
{
|
||||
struct mountpoint *mp;
|
||||
|
||||
list_for_each_entry(mp, &mountpoints, list) {
|
||||
if (!strcmp(mp->path, path))
|
||||
return mp;
|
||||
}
|
||||
|
||||
mp = xzalloc(sizeof(*mp));
|
||||
mp->path = strdup(path);
|
||||
asprintf(&mp->mountpath, "%s/%s", tmppath(), mp->path);
|
||||
list_add_tail(&mp->list, &mountpoints);
|
||||
|
||||
return mp;
|
||||
}
|
||||
|
||||
static void add_root_mountpoint(void)
|
||||
{
|
||||
struct mountpoint *mp;
|
||||
|
||||
mp = xzalloc(sizeof(*mp));
|
||||
mp->path = strdup("");
|
||||
asprintf(&mp->mountpath, "%s/root", tmppath());
|
||||
list_add_tail(&mp->list, &mountpoints);
|
||||
}
|
||||
|
||||
static int collect_mountpoints(void)
|
||||
{
|
||||
struct image *image;
|
||||
struct mountpoint *mp;
|
||||
int ret;
|
||||
|
||||
add_root_mountpoint();
|
||||
|
||||
ret = systemp(NULL, "mkdir -p %s", tmppath());
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = systemp(NULL, "cp -a %s %s/root", rootpath(), tmppath());
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(image, &images, list) {
|
||||
if (image->mountpoint)
|
||||
image->mp = add_mountpoint(image->mountpoint);
|
||||
}
|
||||
|
||||
list_for_each_entry(mp, &mountpoints, list) {
|
||||
if (!strlen(mp->path))
|
||||
continue;
|
||||
ret = systemp(NULL, "mv %s/root/%s %s", tmppath(), mp->path, tmppath());
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_tmp_path(void)
|
||||
{
|
||||
const char *tmp = tmppath();
|
||||
int ret;
|
||||
DIR *dir;
|
||||
int i = 0;
|
||||
|
||||
if (!tmp) {
|
||||
fprintf(stderr, "tmppath not set. aborting\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dir = opendir(tmp);
|
||||
if (!dir) {
|
||||
ret = systemp(NULL, "mkdir -p %s", tmppath());
|
||||
if (ret)
|
||||
exit(1);
|
||||
closedir(dir);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!readdir(dir))
|
||||
break;
|
||||
i++;
|
||||
if (i > 2) {
|
||||
fprintf(stderr, "tmppath '%s' exists and is not empty\n",
|
||||
tmp);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
systemp(NULL, "rm -rf %s/*", tmppath());
|
||||
}
|
||||
|
||||
static cfg_opt_t top_opts[] = {
|
||||
CFG_SEC("image", NULL, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_SEC("flash", flashchip_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_SEC("config", NULL, CFGF_MULTI),
|
||||
CFG_FUNC("include", &cfg_include),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int num_images;
|
||||
int ret;
|
||||
cfg_opt_t *imageopts = xzalloc((ARRAY_SIZE(image_common_opts) +
|
||||
ARRAY_SIZE(handlers) + 1) * sizeof(cfg_opt_t));;
|
||||
int start;
|
||||
struct image *image;
|
||||
char *str;
|
||||
cfg_t *cfg;
|
||||
struct partition *part;
|
||||
|
||||
cfg_opt_t image_end[] = {
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
memcpy(imageopts, image_common_opts, sizeof(image_common_opts));
|
||||
|
||||
start = ARRAY_SIZE(image_common_opts);
|
||||
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
|
||||
struct image_handler *handler = handlers[i];
|
||||
cfg_opt_t image_tmp[] = {
|
||||
CFG_SEC("dummy", NULL, CFGF_MULTI),
|
||||
};
|
||||
|
||||
image_tmp[0].name = handler->type;
|
||||
image_tmp[0].subopts = handler->opts;
|
||||
|
||||
memcpy(&imageopts[start + i], image_tmp, sizeof(cfg_opt_t));
|
||||
}
|
||||
|
||||
memcpy(&imageopts[start + i], &image_end[0], sizeof(cfg_opt_t));
|
||||
|
||||
top_opts[0].subopts = imageopts;
|
||||
|
||||
init_config();
|
||||
top_opts[2].subopts = get_config_opts();
|
||||
|
||||
cfg = cfg_init(top_opts, CFGF_NONE);
|
||||
if (cfg_parse(cfg, "test.config") == CFG_PARSE_ERROR)
|
||||
goto err_out;
|
||||
|
||||
set_config_opts(argc, argv, cfg);
|
||||
|
||||
check_tmp_path();
|
||||
|
||||
ret = systemp(NULL, "rm -rf %s/*", tmppath());
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
parse_flashes(cfg);
|
||||
|
||||
num_images = cfg_size(cfg, "image");
|
||||
|
||||
for (i = 0; i < num_images; i++) {
|
||||
cfg_t *imagesec = cfg_getnsec(cfg, "image", i);
|
||||
image = xzalloc(sizeof *image);
|
||||
INIT_LIST_HEAD(&image->partitions);
|
||||
list_add_tail(&image->list, &images);
|
||||
image->file = cfg_title(imagesec);
|
||||
image->name = cfg_getstr(imagesec, "name");
|
||||
image->size = cfg_getint_suffix(imagesec, "size");
|
||||
image->offset = cfg_getint_suffix(imagesec, "offset");
|
||||
image->mountpoint = cfg_getstr(imagesec, "mountpoint");
|
||||
if (image->mountpoint && *image->mountpoint == '/')
|
||||
image->mountpoint++;
|
||||
str = cfg_getstr(imagesec, "flashtype");
|
||||
if (str)
|
||||
image->flash_type = flash_type_get(str);
|
||||
image_get_type(image, imagesec);
|
||||
parse_partitions(image, imagesec);
|
||||
}
|
||||
|
||||
/* check if each partition has a corresponding image */
|
||||
list_for_each_entry(image, &images, list) {
|
||||
list_for_each_entry(part, &image->partitions, list) {
|
||||
struct image *i = image_get(part->image);
|
||||
if (!i) {
|
||||
image_error(image, "no rule to generate %s\n", part->image);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* propagate flash types to partitions */
|
||||
ret = set_flash_type();
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
ret = collect_mountpoints();
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
list_for_each_entry(image, &images, list) {
|
||||
if (image->handler->setup) {
|
||||
ret = image->handler->setup(image, image->imagesec);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(image, &images, list) {
|
||||
ret = image_generate(image);
|
||||
if (ret) {
|
||||
printf("failed to generate %s\n", image->file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup();
|
||||
exit(0);
|
||||
|
||||
err_out:
|
||||
cleanup();
|
||||
exit(1);
|
||||
}
|
||||
|
116
genimage.h
Normal file
116
genimage.h
Normal file
@ -0,0 +1,116 @@
|
||||
#ifndef __PTX_IMAGE_H
|
||||
#define __PTX_IMAGE_H
|
||||
|
||||
#include "list.h"
|
||||
|
||||
struct image_handler;
|
||||
|
||||
struct image *image_get(const char *filename);
|
||||
|
||||
int systemp(struct image *image, const char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
|
||||
void error(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
|
||||
void image_error(struct image *image, const char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
|
||||
void image_log(struct image *image, int level, const char *fmt, ...) __attribute__ ((format(printf, 3, 4)));
|
||||
|
||||
const char *imagepath(void);
|
||||
const char *inputpath(void);
|
||||
const char *rootpath(void);
|
||||
const char *tmppath(void);
|
||||
const char *mountpath(struct image *);
|
||||
struct flash_type;
|
||||
|
||||
struct mountpoint {
|
||||
char *path;
|
||||
struct list_head list;
|
||||
char *mountpath;
|
||||
};
|
||||
|
||||
struct partition {
|
||||
unsigned long long offset;
|
||||
unsigned long long size;
|
||||
unsigned char partition_type;
|
||||
const char *image;
|
||||
struct list_head list;
|
||||
int autoresize;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct image {
|
||||
const char *name;
|
||||
const char *file;
|
||||
unsigned long long size;
|
||||
unsigned long long offset;
|
||||
const char *mountpoint;
|
||||
unsigned char partition_type;
|
||||
void *handler_priv;
|
||||
struct image_handler *handler;
|
||||
struct list_head list;
|
||||
int done;
|
||||
struct flash_type *flash_type;
|
||||
cfg_t *imagesec;
|
||||
struct list_head partitions;
|
||||
struct mountpoint *mp;
|
||||
};
|
||||
|
||||
struct image_handler {
|
||||
char *type;
|
||||
int (*setup)(struct image *i, cfg_t *cfg);
|
||||
int (*generate)(struct image *i);
|
||||
cfg_opt_t *opts;
|
||||
};
|
||||
|
||||
struct flash_type {
|
||||
const char *name;
|
||||
int pebsize;
|
||||
int lebsize;
|
||||
int numpebs;
|
||||
int minimum_io_unit_size;
|
||||
int vid_header_offset;
|
||||
int sub_page_size;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct flash_type *flash_type_get(const char *name);
|
||||
int image_set_flash_type(struct image *image, struct flash_type *type);
|
||||
|
||||
extern struct image_handler jffs2_handler;
|
||||
extern struct image_handler flash_handler;
|
||||
extern struct image_handler tar_handler;
|
||||
extern struct image_handler ubi_handler;
|
||||
extern struct image_handler ubifs_handler;
|
||||
extern struct image_handler hdimage_handler;
|
||||
extern struct image_handler ext2_handler;
|
||||
extern struct image_handler file_handler;
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
|
||||
/**
|
||||
* container_of - cast a member of a structure out to the containing structure
|
||||
* @ptr: the pointer to the member.
|
||||
* @type: the type of the container struct this is embedded in.
|
||||
* @member: the name of the member within the struct.
|
||||
*
|
||||
*/
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
void *xzalloc(size_t n);
|
||||
unsigned long long strtoul_suffix(const char *str, char **endp, int base);
|
||||
|
||||
int init_config(void);
|
||||
cfg_opt_t *get_config_opts(void);
|
||||
const char *get_opt(const char *name);
|
||||
int set_config_opts(int argc, char *argv[], cfg_t *cfg);
|
||||
|
||||
enum pad_mode {
|
||||
MODE_APPEND,
|
||||
MODE_OVERWRITE,
|
||||
};
|
||||
|
||||
int pad_file(const char *infile, const char *outfile, size_t size,
|
||||
unsigned char fillpattern, enum pad_mode mode);
|
||||
|
||||
#endif /* __PTX_IMAGE_H */
|
39
image-ext2.c
Normal file
39
image-ext2.c
Normal file
@ -0,0 +1,39 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
static int ext2_generate(struct image *image)
|
||||
{
|
||||
int ret;
|
||||
char *extraargs = cfg_getstr(image->imagesec, "extraargs");
|
||||
|
||||
ret = systemp(image, "%s -d %s --size-in-blocks=%lld %s/%s %s",
|
||||
get_opt("genext2fs"),
|
||||
mountpath(image), image->size / 1024, imagepath(), image->file,
|
||||
extraargs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ext2_setup(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cfg_opt_t ext2_opts[] = {
|
||||
CFG_STR("extraargs", "", CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
struct image_handler ext2_handler = {
|
||||
.type = "ext2",
|
||||
.generate = ext2_generate,
|
||||
.setup = ext2_setup,
|
||||
.opts = ext2_opts,
|
||||
};
|
||||
|
47
image-file.c
Normal file
47
image-file.c
Normal file
@ -0,0 +1,47 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
struct file {
|
||||
char *name;
|
||||
};
|
||||
|
||||
static int file_generate(struct image *image)
|
||||
{
|
||||
struct file *f = image->handler_priv;
|
||||
int ret;
|
||||
|
||||
ret = systemp(image, "cp %s/%s %s/%s", inputpath(), f->name, imagepath(), image->file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int file_setup(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
struct file *f = xzalloc(sizeof(*f));
|
||||
|
||||
f->name = cfg_getstr(cfg, "name");
|
||||
if (!f->name)
|
||||
f->name = strdup(image->file);
|
||||
|
||||
image->handler_priv = f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cfg_opt_t file_opts[] = {
|
||||
CFG_STR("name", NULL, CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
struct image_handler file_handler = {
|
||||
.type = "file",
|
||||
.generate = file_generate,
|
||||
.setup = file_setup,
|
||||
.opts = file_opts,
|
||||
};
|
||||
|
100
image-flash.c
Normal file
100
image-flash.c
Normal file
@ -0,0 +1,100 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "genimage.h"
|
||||
|
||||
struct flash_image {
|
||||
};
|
||||
|
||||
static int flash_generate(struct image *image)
|
||||
{
|
||||
struct partition *part;
|
||||
struct stat s;
|
||||
int ret;
|
||||
char *buf;
|
||||
|
||||
list_for_each_entry(part, &image->partitions, list) {
|
||||
struct image *child;
|
||||
|
||||
child = image_get(part->image);
|
||||
if (!child) {
|
||||
image_error(image, "could not find %s\n", part->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
asprintf(&buf, "%s/%s", imagepath(), part->image);
|
||||
ret = stat(buf, &s);
|
||||
free(buf);
|
||||
if (ret)
|
||||
return -errno;
|
||||
|
||||
if (s.st_size > part->size) {
|
||||
image_error(image, "image file %s for partition %s is bigger than partition (%ld > %lld)\n",
|
||||
child->file, part->name, s.st_size, part->size);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_setup(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
struct flash_image *f = xzalloc(sizeof(*f));
|
||||
struct partition *part;
|
||||
int last = 0;
|
||||
unsigned long long partsize = 0, flashsize;
|
||||
|
||||
image->handler_priv = f;
|
||||
|
||||
if (!image->flash_type) {
|
||||
image_error(image, "no flash type given\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flashsize = image->flash_type->pebsize * image->flash_type->numpebs;
|
||||
|
||||
list_for_each_entry(part, &image->partitions, list) {
|
||||
if (last) {
|
||||
image_error(image, "only last partition may have size 0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!part->size) {
|
||||
last = 1;
|
||||
if (partsize > flashsize)
|
||||
goto err_exceed;
|
||||
part->size = flashsize - partsize;
|
||||
}
|
||||
|
||||
partsize += part->size;
|
||||
}
|
||||
|
||||
if (partsize > flashsize) {
|
||||
err_exceed:
|
||||
image_error(image, "size of partitions (%lld) exceeds flash size (%lld)\n",
|
||||
partsize, flashsize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cfg_opt_t flash_opts[] = {
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
struct image_handler flash_handler = {
|
||||
.type = "flash",
|
||||
.generate = flash_generate,
|
||||
.setup = flash_setup,
|
||||
.opts = flash_opts,
|
||||
};
|
||||
|
89
image-hd.c
Normal file
89
image-hd.c
Normal file
@ -0,0 +1,89 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
static int hdimage_generate(struct image *image)
|
||||
{
|
||||
struct partition *part;
|
||||
enum pad_mode mode = MODE_OVERWRITE;
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(part, &image->partitions, list) {
|
||||
struct image *child;
|
||||
char *infile, *outfile;
|
||||
|
||||
child = image_get(part->image);
|
||||
if (!child) {
|
||||
image_error(image, "could not find %s\n", part->image);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
asprintf(&infile, "%s/%s", imagepath(), part->image);
|
||||
asprintf(&outfile, "%s/%s", imagepath(), image->file);
|
||||
|
||||
if (part->offset) {
|
||||
ret = pad_file(NULL, outfile, part->offset, 0x0, mode);
|
||||
if (ret) {
|
||||
image_error(image, "failed to pad image to size %lld\n",
|
||||
part->offset);
|
||||
free(infile);
|
||||
free(outfile);
|
||||
return ret;
|
||||
}
|
||||
mode = MODE_APPEND;
|
||||
}
|
||||
|
||||
ret = pad_file(infile, outfile, part->size, 0x0, mode);
|
||||
|
||||
free(infile);
|
||||
free(outfile);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
mode = MODE_APPEND;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdimage_setup(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
struct partition *part;
|
||||
unsigned long long now = 0;
|
||||
|
||||
list_for_each_entry(part, &image->partitions, list) {
|
||||
if (part->offset) {
|
||||
if (now > part->offset) {
|
||||
image_error(image, "part %s overlaps with previous partition\n",
|
||||
part->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
now = part->offset + part->size;
|
||||
} else {
|
||||
now = now + part->size;
|
||||
}
|
||||
}
|
||||
|
||||
if (now > image->size) {
|
||||
image_error(image, "partitions exceed device size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cfg_opt_t hdimage_opts[] = {
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
struct image_handler hdimage_handler = {
|
||||
.type = "hdimage",
|
||||
.generate = hdimage_generate,
|
||||
.setup = hdimage_setup,
|
||||
.opts = hdimage_opts,
|
||||
};
|
||||
|
46
image-jffs2.c
Normal file
46
image-jffs2.c
Normal file
@ -0,0 +1,46 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
static int jffs2_generate(struct image *image)
|
||||
{
|
||||
int ret;
|
||||
char *extraargs;
|
||||
|
||||
if (!image->flash_type) {
|
||||
printf("no flash type given for %s\n", image->file);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
extraargs = cfg_getstr(image->imagesec, "extraargs");
|
||||
|
||||
ret = systemp(image, "%s --eraseblock=%d -d %s -o %s/%s %s",
|
||||
get_opt("mkfsjffs2"),
|
||||
image->flash_type->pebsize, mountpath(image), imagepath(), image->file,
|
||||
extraargs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int jffs2_setup(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cfg_opt_t jffs2_opts[] = {
|
||||
CFG_STR("extraargs", "", CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
struct image_handler jffs2_handler = {
|
||||
.type = "jffs2",
|
||||
.generate = jffs2_generate,
|
||||
.setup = jffs2_setup,
|
||||
.opts = jffs2_opts,
|
||||
};
|
||||
|
43
image-tar.c
Normal file
43
image-tar.c
Normal file
@ -0,0 +1,43 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
static int tar_generate(struct image *image)
|
||||
{
|
||||
int ret;
|
||||
char *comp = "";
|
||||
|
||||
if (strstr(image->file, ".tar.gz") || strstr(image->file, "tgz"))
|
||||
comp = "z";
|
||||
if (strstr(image->file, ".tar.bz2"))
|
||||
comp = "j";
|
||||
|
||||
ret = systemp(image, "%s c%s -f %s/%s -C %s/%s .",
|
||||
get_opt("tar"),
|
||||
comp,
|
||||
imagepath(), image->file, rootpath(), image->mountpoint);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tar_setup(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cfg_opt_t tar_opts[] = {
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
struct image_handler tar_handler = {
|
||||
.type = "tar",
|
||||
.generate = tar_generate,
|
||||
.setup = tar_setup,
|
||||
.opts = tar_opts,
|
||||
};
|
||||
|
99
image-ubi.c
Normal file
99
image-ubi.c
Normal file
@ -0,0 +1,99 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
struct ubi {
|
||||
};
|
||||
|
||||
static int ubi_generate(struct image *image)
|
||||
{
|
||||
int ret;
|
||||
FILE *fini;
|
||||
char *tempfile;
|
||||
int i = 0;
|
||||
struct partition *part;
|
||||
char *extraargs = cfg_getstr(image->imagesec, "extraargs");
|
||||
|
||||
asprintf(&tempfile, "%s/ubifs.ini", tmppath());
|
||||
if (!tempfile)
|
||||
return -ENOMEM;
|
||||
|
||||
fini = fopen(tempfile, "w");
|
||||
if (!fini) {
|
||||
image_error(image, "creating temp file failed: %s\n", strerror(errno));
|
||||
return -errno;
|
||||
|
||||
}
|
||||
|
||||
list_for_each_entry(part, &image->partitions, list) {
|
||||
struct image *child;
|
||||
child = image_get(part->image);
|
||||
if (!child) {
|
||||
image_error(image, "could not find %s\n", part->image);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fprintf(fini, "[%s]\n", part->name);
|
||||
fprintf(fini, "mode=ubi\n");
|
||||
fprintf(fini, "image=%s/%s\n", imagepath(), child->file);
|
||||
fprintf(fini, "vol_id=%d\n", i);
|
||||
fprintf(fini, "vol_size=%lld\n", child->size);
|
||||
fprintf(fini, "vol_type=dynamic\n");
|
||||
fprintf(fini, "vol_name=%s\n", part->name);
|
||||
fprintf(fini, "autoresize=%s\n", part->autoresize ? "true" : "false");
|
||||
fprintf(fini, "vol_alignment=1\n");
|
||||
i++;
|
||||
}
|
||||
|
||||
fclose(fini);
|
||||
|
||||
ret = systemp(image, "%s -s %d -O %d -p %d -m %d -o %s/%s %s %s",
|
||||
get_opt("ubinize"),
|
||||
image->flash_type->sub_page_size,
|
||||
image->flash_type->vid_header_offset,
|
||||
image->flash_type->pebsize,
|
||||
image->flash_type->minimum_io_unit_size,
|
||||
imagepath(),
|
||||
image->file,
|
||||
tempfile,
|
||||
extraargs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ubi_setup(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
struct ubi *ubi = xzalloc(sizeof(*ubi));
|
||||
int autoresize = 0;
|
||||
struct partition *part;
|
||||
|
||||
image->handler_priv = ubi;
|
||||
|
||||
list_for_each_entry(part, &image->partitions, list)
|
||||
autoresize += part->autoresize;
|
||||
|
||||
if (autoresize > 1) {
|
||||
image_error(image, "more than one volume has the autoresize flag set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cfg_opt_t ubi_opts[] = {
|
||||
CFG_STR("extraargs", "", CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
struct image_handler ubi_handler = {
|
||||
.type = "ubi",
|
||||
.generate = ubi_generate,
|
||||
.setup = ubi_setup,
|
||||
.opts = ubi_opts,
|
||||
};
|
||||
|
47
image-ubifs.c
Normal file
47
image-ubifs.c
Normal file
@ -0,0 +1,47 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
static int ubifs_generate(struct image *image)
|
||||
{
|
||||
int lebcount;
|
||||
int ret;
|
||||
char *extraargs = cfg_getstr(image->imagesec, "extraargs");
|
||||
|
||||
lebcount = image->size / image->flash_type->lebsize;
|
||||
|
||||
ret = systemp(image, "%s -d %s -e %d -m %d -c %d -o %s/%s %s",
|
||||
get_opt("mkfsubifs"),
|
||||
mountpath(image),
|
||||
image->flash_type->lebsize,
|
||||
image->flash_type->minimum_io_unit_size,
|
||||
lebcount,
|
||||
imagepath(),
|
||||
image->file,
|
||||
extraargs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ubifs_setup(struct image *image, cfg_t *cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cfg_opt_t ubifs_opts[] = {
|
||||
CFG_STR("extraargs", "", CFGF_NONE),
|
||||
CFG_STR("autoresize", "", CFGF_NONE),
|
||||
CFG_END()
|
||||
};
|
||||
|
||||
struct image_handler ubifs_handler = {
|
||||
.type = "ubifs",
|
||||
.generate = ubifs_generate,
|
||||
.setup = ubifs_setup,
|
||||
.opts = ubifs_opts,
|
||||
};
|
||||
|
605
list.h
Normal file
605
list.h
Normal file
@ -0,0 +1,605 @@
|
||||
#ifndef _LINUX_LIST_H
|
||||
#define _LINUX_LIST_H
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
#define LIST_POISON1 ((void *) 0x00100100)
|
||||
#define LIST_POISON2 ((void *) 0x00200200)
|
||||
static inline void prefetch(const void *x) {;}
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
#ifndef CONFIG_DEBUG_LIST
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
#else
|
||||
extern void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
#ifndef CONFIG_DEBUG_LIST
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
#else
|
||||
extern void list_add(struct list_head *new, struct list_head *head);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty() on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
#ifndef CONFIG_DEBUG_LIST
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = LIST_POISON1;
|
||||
entry->prev = LIST_POISON2;
|
||||
}
|
||||
#else
|
||||
extern void list_del(struct list_head *entry);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* list_replace - replace old entry by new one
|
||||
* @old : the element to be replaced
|
||||
* @new : the new element to insert
|
||||
*
|
||||
* If @old was empty, it will be overwritten.
|
||||
*/
|
||||
static inline void list_replace(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
new->next = old->next;
|
||||
new->next->prev = new;
|
||||
new->prev = old->prev;
|
||||
new->prev->next = new;
|
||||
}
|
||||
|
||||
static inline void list_replace_init(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
list_replace(old, new);
|
||||
INIT_LIST_HEAD(old);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_is_last - tests whether @list is the last entry in list @head
|
||||
* @list: the entry to test
|
||||
* @head: the head of the list
|
||||
*/
|
||||
static inline int list_is_last(const struct list_head *list,
|
||||
const struct list_head *head)
|
||||
{
|
||||
return list->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty_careful - tests whether a list is empty and not being modified
|
||||
* @head: the list to test
|
||||
*
|
||||
* Description:
|
||||
* tests whether a list is empty _and_ checks that no other CPU might be
|
||||
* in the process of modifying either member (next or prev)
|
||||
*
|
||||
* NOTE: using list_empty_careful() without synchronization
|
||||
* can only be safe if the only activity that can happen
|
||||
* to the list entry is list_del_init(). Eg. it cannot be used
|
||||
* if another CPU could re-list_add() it.
|
||||
*/
|
||||
static inline int list_empty_careful(const struct list_head *head)
|
||||
{
|
||||
struct list_head *next = head->next;
|
||||
return (next == head) && (next == head->prev);
|
||||
}
|
||||
|
||||
static inline void __list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* list_first_entry - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* __list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*
|
||||
* This variant differs from list_for_each() in that it's the
|
||||
* simplest possible list iteration code, no prefetching is done.
|
||||
* Use this for code that knows the list to be very short (empty
|
||||
* or 1 entry) most of the time.
|
||||
*/
|
||||
#define __list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_prev - iterate over a list backwards
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
|
||||
pos = pos->prev)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||
prefetch(pos->member.next), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member); \
|
||||
prefetch(pos->member.prev), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
||||
* @pos: the type * to use as a start point
|
||||
* @head: the head of the list
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
||||
*/
|
||||
#define list_prepare_entry(pos, head, member) \
|
||||
((pos) ? : list_entry(head, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue - continue iteration over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Continue to iterate over list of given type, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define list_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
prefetch(pos->member.next), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_from - iterate over list of given type from the current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Iterate over list of given type, continuing from current position.
|
||||
*/
|
||||
#define list_for_each_entry_from(pos, head, member) \
|
||||
for (; prefetch(pos->member.next), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_continue
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Iterate over list of given type, continuing after current point,
|
||||
* safe against removal of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_from
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Iterate over list of given type from current point, safe against
|
||||
* removal of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_from(pos, n, head, member) \
|
||||
for (n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_reverse
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Iterate backwards over list of given type, safe against removal
|
||||
* of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_add_sort - add a new entry to a sorted list
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it in
|
||||
* @compare: Compare function to compare two list entries
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_sort(struct list_head *new, struct list_head *head,
|
||||
int (*compare)(struct list_head *a, struct list_head *b))
|
||||
{
|
||||
struct list_head *pos, *insert = head;
|
||||
|
||||
list_for_each(pos, head) {
|
||||
if (compare(pos, new) < 0)
|
||||
continue;
|
||||
insert = pos;
|
||||
break;
|
||||
}
|
||||
|
||||
list_add_tail(new, insert);
|
||||
}
|
||||
|
||||
/*
|
||||
* Double linked lists with a single pointer list head.
|
||||
* Mostly useful for hash tables where the two pointer list head is
|
||||
* too wasteful.
|
||||
* You lose the ability to access the tail in O(1).
|
||||
*/
|
||||
|
||||
struct hlist_head {
|
||||
struct hlist_node *first;
|
||||
};
|
||||
|
||||
struct hlist_node {
|
||||
struct hlist_node *next, **pprev;
|
||||
};
|
||||
|
||||
#define HLIST_HEAD_INIT { .first = NULL }
|
||||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
||||
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
|
||||
static inline void INIT_HLIST_NODE(struct hlist_node *h)
|
||||
{
|
||||
h->next = NULL;
|
||||
h->pprev = NULL;
|
||||
}
|
||||
|
||||
static inline int hlist_unhashed(const struct hlist_node *h)
|
||||
{
|
||||
return !h->pprev;
|
||||
}
|
||||
|
||||
static inline int hlist_empty(const struct hlist_head *h)
|
||||
{
|
||||
return !h->first;
|
||||
}
|
||||
|
||||
static inline void __hlist_del(struct hlist_node *n)
|
||||
{
|
||||
struct hlist_node *next = n->next;
|
||||
struct hlist_node **pprev = n->pprev;
|
||||
*pprev = next;
|
||||
if (next)
|
||||
next->pprev = pprev;
|
||||
}
|
||||
|
||||
static inline void hlist_del(struct hlist_node *n)
|
||||
{
|
||||
__hlist_del(n);
|
||||
n->next = LIST_POISON1;
|
||||
n->pprev = LIST_POISON2;
|
||||
}
|
||||
|
||||
static inline void hlist_del_init(struct hlist_node *n)
|
||||
{
|
||||
if (!hlist_unhashed(n)) {
|
||||
__hlist_del(n);
|
||||
INIT_HLIST_NODE(n);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
struct hlist_node *first = h->first;
|
||||
n->next = first;
|
||||
if (first)
|
||||
first->pprev = &n->next;
|
||||
h->first = n;
|
||||
n->pprev = &h->first;
|
||||
}
|
||||
|
||||
/* next must be != NULL */
|
||||
static inline void hlist_add_before(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
n->pprev = next->pprev;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
*(n->pprev) = n;
|
||||
}
|
||||
|
||||
static inline void hlist_add_after(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
next->next = n->next;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
|
||||
if(next->next)
|
||||
next->next->pprev = &next->next;
|
||||
}
|
||||
|
||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
|
||||
#define hlist_for_each(pos, head) \
|
||||
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
|
||||
pos = pos->next)
|
||||
|
||||
#define hlist_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
||||
pos = n)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry - iterate over list of given type
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry(tpos, pos, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_continue(tpos, pos, member) \
|
||||
for (pos = (pos)->next; \
|
||||
pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_from(tpos, pos, member) \
|
||||
for (; pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @n: another &struct hlist_node to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
pos && ({ n = pos->next; 1; }) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = n)
|
||||
|
||||
#endif
|
178
test.config
Normal file
178
test.config
Normal file
@ -0,0 +1,178 @@
|
||||
|
||||
include("flash.conf")
|
||||
|
||||
#-----------------------------------
|
||||
|
||||
image data.tgz {
|
||||
tar {}
|
||||
mountpoint = "/data"
|
||||
}
|
||||
|
||||
image nand-pcm038.img {
|
||||
flash {
|
||||
}
|
||||
flashtype = "nand-64M-512"
|
||||
partition barebox {
|
||||
image = "barebox-pcm038.bin"
|
||||
size = 512K
|
||||
}
|
||||
partition bareboxenv {
|
||||
image = "bareboxenv-pcm038.bin"
|
||||
size = 512K
|
||||
}
|
||||
partition kernel {
|
||||
image = "kernel-imx.bin"
|
||||
size = 4M
|
||||
}
|
||||
partition root {
|
||||
image = "root-nand.ubi"
|
||||
size = 20M
|
||||
}
|
||||
partition data {
|
||||
image = "data-nand.ubi"
|
||||
size = 0
|
||||
}
|
||||
}
|
||||
|
||||
image root-nor-32M-64k.jffs2 {
|
||||
name = "root"
|
||||
flashtype = "nor-64M-128k"
|
||||
jffs2 {}
|
||||
size = 24M
|
||||
mountpoint = "/"
|
||||
}
|
||||
|
||||
image data-nor-32M-64k.jffs2 {
|
||||
name = "data"
|
||||
flashtype = "nor-64M-128k"
|
||||
size = 0
|
||||
jffs2 {
|
||||
extraargs = "-l"
|
||||
}
|
||||
mountpoint = "/data"
|
||||
}
|
||||
|
||||
image nand-pcm037.img {
|
||||
flash {
|
||||
}
|
||||
flashtype = "nand-64M-512"
|
||||
partition barebox {
|
||||
image = "barebox-pcm037.bin"
|
||||
size = 512K
|
||||
}
|
||||
partition bareboxenv {
|
||||
image = "bareboxenv-pcm037.bin"
|
||||
size = 512K
|
||||
}
|
||||
partition kernel {
|
||||
image = "kernel-imx.bin"
|
||||
size = 4M
|
||||
}
|
||||
partition root {
|
||||
image = "root-nand.ubi"
|
||||
size = 20M
|
||||
}
|
||||
partition data {
|
||||
image = "data-nand.ubi"
|
||||
size = 0
|
||||
}
|
||||
}
|
||||
|
||||
image data-nand.ubi {
|
||||
ubi {}
|
||||
partition data {
|
||||
autoresize = true
|
||||
image = "data-nand.ubifs"
|
||||
}
|
||||
partition root {
|
||||
image = "data-nand.ubifs"
|
||||
}
|
||||
}
|
||||
|
||||
image data-nand.ubifs {
|
||||
ubifs {}
|
||||
name = "data"
|
||||
size = 128M
|
||||
mountpoint = "/data"
|
||||
}
|
||||
|
||||
image barebox-pcm038.bin {
|
||||
name = "barebox"
|
||||
file {}
|
||||
}
|
||||
|
||||
image bareboxenv-pcm038.bin {
|
||||
name = "bareboxenv"
|
||||
file {}
|
||||
}
|
||||
|
||||
image barebox-pcm037.bin {
|
||||
name = "barebox"
|
||||
file {}
|
||||
}
|
||||
|
||||
image bareboxenv-pcm037.bin {
|
||||
name = "bareboxenv"
|
||||
file {}
|
||||
}
|
||||
|
||||
image kernel-imx.bin {
|
||||
name = "kernel"
|
||||
file {
|
||||
name = "zImage-linux-2.6.39-imx"
|
||||
}
|
||||
}
|
||||
|
||||
image root-nand.ubi {
|
||||
name = "root"
|
||||
ubi {}
|
||||
|
||||
partition root {
|
||||
image = "root-nand.ubifs"
|
||||
}
|
||||
}
|
||||
|
||||
image root-nand.ubifs {
|
||||
name = "root"
|
||||
size = 128M
|
||||
ubifs {}
|
||||
mountpoint = "/"
|
||||
}
|
||||
|
||||
image hdimg.img {
|
||||
hdimage {}
|
||||
|
||||
partition root {
|
||||
offset = 2M
|
||||
size = 128M
|
||||
partition-type = 0x78
|
||||
image = "root.ext2"
|
||||
}
|
||||
partition data {
|
||||
size = 20M
|
||||
partition-type = 0x1a
|
||||
image = "data.ext2"
|
||||
}
|
||||
|
||||
size = 2G
|
||||
}
|
||||
|
||||
image root.ext2 {
|
||||
ext2 {}
|
||||
size = 128M
|
||||
mountpoint = "/"
|
||||
}
|
||||
|
||||
image data.ext2 {
|
||||
ext2 {}
|
||||
size = 20M
|
||||
mountpoint = "/data"
|
||||
}
|
||||
|
||||
config {
|
||||
outputpath = images
|
||||
inputpath = input
|
||||
rootpath = root
|
||||
tmppath = tmp
|
||||
}
|
||||
|
220
util.c
Normal file
220
util.c
Normal file
@ -0,0 +1,220 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <confuse.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "genimage.h"
|
||||
|
||||
void image_error(struct image *image, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *buf;
|
||||
|
||||
va_start (args, fmt);
|
||||
|
||||
vasprintf(&buf, fmt, args);
|
||||
|
||||
va_end (args);
|
||||
|
||||
fprintf(stderr, "%s(%s): %s", image->handler->type, image->file, buf);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void image_log(struct image *image, int level, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *buf;
|
||||
|
||||
va_start (args, fmt);
|
||||
|
||||
vasprintf(&buf, fmt, args);
|
||||
|
||||
va_end (args);
|
||||
|
||||
fprintf(stderr, "%s(%s): %s", image->handler->type, image->file, buf);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, fmt);
|
||||
|
||||
vfprintf(stderr, fmt, args);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
/*
|
||||
* printf wrapper around 'system'
|
||||
*/
|
||||
int systemp(struct image *image, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
va_start (args, fmt);
|
||||
|
||||
vasprintf(&buf, fmt, args);
|
||||
|
||||
va_end (args);
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (image)
|
||||
image_log(image, 1, "cmd: %s\n", buf);
|
||||
else
|
||||
fprintf(stderr, "cmd: %s\n", buf);
|
||||
|
||||
ret = system(buf);
|
||||
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* xzalloc - safely allocate zeroed memory
|
||||
*/
|
||||
void *xzalloc(size_t n)
|
||||
{
|
||||
void *m = malloc(n);
|
||||
|
||||
if (!m) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(m, 0, n);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like simple_strtoul() but handles an optional G, M, K or k
|
||||
* suffix for Gigabyte, Megabyte or Kilobyte
|
||||
*/
|
||||
unsigned long long strtoul_suffix(const char *str, char **endp, int base)
|
||||
{
|
||||
unsigned long long val;
|
||||
char *end;
|
||||
|
||||
val = strtoull(str, &end, base);
|
||||
|
||||
switch (*end) {
|
||||
case 'G':
|
||||
val *= 1024;
|
||||
case 'M':
|
||||
val *= 1024;
|
||||
case 'k':
|
||||
case 'K':
|
||||
val *= 1024;
|
||||
end++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (endp)
|
||||
*endp = (char *)end;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int min(int a, int b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
int pad_file(const char *infile, const char *outfile, size_t size,
|
||||
unsigned char fillpattern, enum pad_mode mode)
|
||||
{
|
||||
FILE *f = NULL, *outf = NULL;
|
||||
void *buf;
|
||||
int now, r;
|
||||
int ret = 0;
|
||||
|
||||
if (infile) {
|
||||
f = fopen(infile, "r");
|
||||
if (!f) {
|
||||
error("open %s: %s\n", infile, strerror(errno));
|
||||
ret = -errno;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
outf = fopen(outfile, mode == MODE_OVERWRITE ? "w" : "a");
|
||||
if (!outf) {
|
||||
error("open %s: %s\n", outfile, strerror(errno));
|
||||
ret = -errno;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
buf = xzalloc(4096);
|
||||
|
||||
if (!infile) {
|
||||
struct stat s;
|
||||
ret = stat(outfile, &s);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
if (s.st_size > size) {
|
||||
ret = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
size = size - s.st_size;
|
||||
goto fill;
|
||||
}
|
||||
|
||||
while (size) {
|
||||
now = min(size, 4096);
|
||||
|
||||
r = fread(buf, 1, now, f);
|
||||
if (r < now)
|
||||
goto fill;
|
||||
|
||||
r = fwrite(buf, 1, now, outf);
|
||||
if (r < now) {
|
||||
ret = -errno;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
size -= now;
|
||||
}
|
||||
|
||||
now = fread(buf, 1, 1, f);
|
||||
if (now == 1) {
|
||||
fprintf(stderr, "pad size smaller than input size\n");
|
||||
ret = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
fill:
|
||||
memset(buf, fillpattern, 4096);
|
||||
|
||||
while (size) {
|
||||
now = min(size, 4096);
|
||||
|
||||
r = fwrite(buf, 1, now, outf);
|
||||
if (r < now) {
|
||||
ret = -errno;
|
||||
goto err_out;
|
||||
}
|
||||
size -= now;
|
||||
}
|
||||
err_out:
|
||||
if (f)
|
||||
fclose(f);
|
||||
if (outf)
|
||||
fclose(outf);
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue
Block a user