#include "libfstools.h"
#include "volume.h"
+#include "snapshot.h"
-#define PATH_MAX 256
-#define OWRT 0x4f575254
-#define DATA 0x44415441
-#define CONF 0x434f4e46
-
-struct file_header {
- uint32_t magic;
- uint32_t type;
- uint32_t seq;
- uint32_t length;
- uint32_t md5[4];
-};
-
-static inline int
-is_config(struct file_header *h)
-{
- return ((h->magic == OWRT) && (h->type == CONF));
-}
-
-static inline int
-valid_file_size(int fs)
-{
- if ((fs > 8 * 1024 * 1204) || (fs <= 0))
- return -1;
-
- return 0;
-}
-
-static void
-hdr_to_be32(struct file_header *hdr)
-{
- uint32_t *h = (uint32_t *) hdr;
- int i;
-
- for (i = 0; i < sizeof(struct file_header) / sizeof(uint32_t); i++)
- h[i] = cpu_to_be32(h[i]);
-}
-
-static void
-be32_to_hdr(struct file_header *hdr)
-{
- uint32_t *h = (uint32_t *) hdr;
- int i;
-
- for (i = 0; i < sizeof(struct file_header) / sizeof(uint32_t); i++)
- h[i] = be32_to_cpu(h[i]);
-}
-
-static int
-pad_file_size(struct volume *v, int size)
-{
- int mod;
-
- size += sizeof(struct file_header);
- mod = size % v->block_size;
- if (mod) {
- size -= mod;
- size += v->block_size;
- }
-
- return size;
-}
-
-static int
+int
verify_file_hash(char *file, uint32_t *hash)
{
uint32_t md5[4];
- if (md5sum(file, md5)) {
- fprintf(stderr, "failed to generate md5 sum\n");
+ if (md5sum(file, md5) <= 0) {
+ ULOG_ERR("failed to generate md5 sum\n");
return -1;
}
if (memcmp(md5, hash, sizeof(md5))) {
- fprintf(stderr, "failed to verify hash of %s.\n", file);
+ ULOG_ERR("failed to verify hash of %s.\n", file);
return -1;
}
return 0;
}
-static int
+int
snapshot_next_free(struct volume *v, uint32_t *seq)
{
struct file_header hdr = { 0 };
do {
if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) {
- fprintf(stderr, "scanning for next free block failed\n");
+ ULOG_ERR("scanning for next free block failed\n");
return 0;
}
return block;
}
-static int
+int
config_find(struct volume *v, struct file_header *conf, struct file_header *sentinel)
{
uint32_t seq;
for (i = (v->size / v->block_size) - 1; i > 0; i--) {
if (volume_read(v, sentinel, i * v->block_size, sizeof(*sentinel))) {
- fprintf(stderr, "failed to read header\n");
+ ULOG_ERR("failed to read header\n");
return -1;
}
be32_to_hdr(sentinel);
return -1;
}
-static int
+int
snapshot_write_file(struct volume *v, int block, char *file, uint32_t seq, uint32_t type)
{
uint32_t md5[4] = { 0 };
int in = 0, len, offset;
int ret = -1;
- if (stat(file, &s) || md5sum(file, md5)) {
- fprintf(stderr, "stat failed on %s\n", file);
+ if (stat(file, &s) || md5sum(file, md5) != s.st_size) {
+ ULOG_ERR("stat failed on %s\n", file);
goto out;
}
if ((block * v->block_size) + pad_file_size(v, s.st_size) > v->size) {
- fprintf(stderr, "upgrade is too big for the flash\n");
+ ULOG_ERR("upgrade is too big for the flash\n");
goto out;
}
volume_erase(v, block * v->block_size, pad_file_size(v, s.st_size));
hdr_to_be32(&hdr);
if (volume_write(v, &hdr, block * v->block_size, sizeof(struct file_header))) {
- fprintf(stderr, "failed to write header\n");
+ ULOG_ERR("failed to write header\n");
goto out;
}
in = open(file, O_RDONLY);
if (in < 1) {
- fprintf(stderr, "failed to open %s\n", file);
+ ULOG_ERR("failed to open %s\n", file);
goto out;
}
return ret;
}
-static int
+int
snapshot_read_file(struct volume *v, int block, char *file, uint32_t type)
{
struct file_header hdr;
int out, offset = 0;
if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) {
- fprintf(stderr, "failed to read header\n");
+ ULOG_ERR("failed to read header\n");
return -1;
}
be32_to_hdr(&hdr);
out = open(file, O_WRONLY | O_CREAT, 0700);
if (!out) {
- fprintf(stderr, "failed to open %s\n", file);
+ ULOG_ERR("failed to open %s\n", file);
return -1;
}
+ offset = block * v->block_size + sizeof(hdr);
+
while (hdr.length > 0) {
int len = sizeof(buffer);
if (hdr.length < len)
len = hdr.length;
- if ((volume_read(v, buffer, offset, len) != len) || (write(out, buffer, len) != len))
+ if (volume_read(v, buffer, offset, len))
+ return -1;
+ if (write(out, buffer, len) != len)
return -1;
-
offset += len;
hdr.length -= len;
}
close(out);
if (verify_file_hash(file, hdr.md5)) {
- fprintf(stderr, "md5 verification failed\n");
+ ULOG_ERR("md5 verification failed\n");
unlink(file);
return 0;
}
return block;
}
-static int
+int
sentinel_write(struct volume *v, uint32_t _seq)
{
int ret, block;
uint32_t seq;
if (stat("/tmp/config.tar.gz", &s)) {
- fprintf(stderr, "failed to stat /tmp/config.tar.gz\n");
+ ULOG_ERR("failed to stat /tmp/config.tar.gz\n");
return -1;
}
ret = snapshot_write_file(v, block, "/tmp/config.tar.gz", seq, CONF);
if (ret)
- fprintf(stderr, "failed to write sentinel\n");
+ ULOG_ERR("failed to write sentinel\n");
else
- fprintf(stderr, "wrote /tmp/config.tar.gz sentinel\n");
+ ULOG_INFO("wrote /tmp/config.tar.gz sentinel\n");
return ret;
}
-static int
+int
volatile_write(struct volume *v, uint32_t _seq)
{
int block, ret;
ret = snapshot_write_file(v, block, "/tmp/config.tar.gz", seq, CONF);
if (ret)
- fprintf(stderr, "failed to write /tmp/config.tar.gz\n");
+ ULOG_ERR("failed to write /tmp/config.tar.gz\n");
else
- fprintf(stderr, "wrote /tmp/config.tar.gz\n");
+ ULOG_INFO("wrote /tmp/config.tar.gz\n");
return ret;
}
static int
-snapshot_sync(void)
+snapshot_sync(struct volume *v)
{
- struct volume *v = volume_find("rootfs_data");
struct file_header sentinel, conf;
int next, block = 0;
uint32_t seq;
- if (!v)
- return -1;
-
next = snapshot_next_free(v, &seq);
block = config_find(v, &conf, &sentinel);
if (is_config(&conf) && conf.seq != seq) {
}
if (!is_config(&conf) && !is_config(&sentinel)) {
- // fprintf(stderr, "no config found\n");
+ // ULOG_ERR("no config found\n");
} else if (((is_config(&conf) && is_config(&sentinel)) &&
(memcmp(conf.md5, sentinel.md5, sizeof(conf.md5)) || (conf.seq != sentinel.seq))) ||
(is_config(&conf) && !is_config(&sentinel))) {
int ret = snapshot_read_file(v, next, "/tmp/config.tar.gz", CONF);
if (ret > 0) {
if (sentinel_write(v, conf.seq))
- fprintf(stderr, "failed to write sentinel data");
+ ULOG_ERR("failed to write sentinel data");
}
} else if (!is_config(&conf) && is_config(&sentinel) && next) {
int ret = snapshot_read_file(v, block, "/tmp/config.tar.gz", CONF);
if (ret > 0)
if (volatile_write(v, sentinel.seq))
- fprintf(stderr, "failed to write sentinel data");
+ ULOG_ERR("failed to write sentinel data");
} else
- fprintf(stderr, "config in sync\n");
+ ULOG_INFO("config in sync\n");
unlink("/tmp/config.tar.gz");
}
int
-mount_snapshot(void)
+mount_snapshot(struct volume *v)
{
- snapshot_sync();
+ snapshot_sync(v);
setenv("SNAPSHOT", "magic", 1);
_ramoverlay("/rom", "/overlay");
- system("/sbin/snapshot unpack");
+ if (system("/sbin/snapshot unpack") == -1) {
+ perror("system");
+ return -1;
+ }
foreachdir("/overlay/", handle_whiteout);
mkdir("/volatile", 0700);
_ramoverlay("/rom", "/volatile");
mount_move("/rom/volatile", "/volatile", "");
mount_move("/rom/rom", "/rom", "");
- system("/sbin/snapshot config_unpack");
+ if (system("/sbin/snapshot config_unpack")) {
+ perror("system");
+ return -1;
+ }
foreachdir("/volatile/", handle_whiteout);
unsetenv("SNAPSHOT");
return -1;