initial import

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2011-06-27 08:39:51 +02:00
commit 7e5122f621
16 changed files with 2355 additions and 0 deletions

14
Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}