libfstools: accept volume as argument in most calls
[project/fstools.git] / libfstools / snapshot.c
index bcbce94..f2ee0cd 100644 (file)
 #include <libubox/blob.h>
 #include <libubox/md5.h>
 
-#include "../fs-state.h"
+#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];
@@ -114,7 +52,7 @@ verify_file_hash(char *file, uint32_t *hash)
        return 0;
 }
 
-static int
+int
 snapshot_next_free(struct volume *v, uint32_t *seq)
 {
        struct file_header hdr = { 0 };
@@ -144,7 +82,7 @@ snapshot_next_free(struct volume *v, uint32_t *seq)
        return block;
 }
 
-static int
+int
 config_find(struct volume *v, struct file_header *conf, struct file_header *sentinel)
 {
        uint32_t seq;
@@ -172,44 +110,7 @@ config_find(struct volume *v, struct file_header *conf, struct file_header *sent
        return -1;
 }
 
-static int
-snapshot_info(void)
-{
-       struct volume *v = volume_find("rootfs_data");
-       struct file_header hdr = { 0 }, conf;
-       int block = 0;
-
-       if (!v)
-               return -1;
-
-       fprintf(stderr, "sectors:\t%llu, block_size:\t%dK\n", v->size / v->block_size, v->block_size / 1024);
-       do {
-               if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) {
-                       fprintf(stderr, "scanning for next free block failed\n");
-                       return 0;
-               }
-
-               be32_to_hdr(&hdr);
-
-               if (hdr.magic != OWRT)
-                       break;
-
-               if (hdr.type == DATA)
-                       fprintf(stderr, "block %d:\tsnapshot entry, size: %d, sectors: %d, sequence: %d\n", block,  hdr.length, pad_file_size(v, hdr.length) / v->block_size, hdr.seq);
-               else if (hdr.type == CONF)
-                       fprintf(stderr, "block %d:\tvolatile entry, size: %d, sectors: %d, sequence: %d\n", block,  hdr.length, pad_file_size(v, hdr.length) / v->block_size, hdr.seq);
-
-               if (hdr.type == DATA && !valid_file_size(hdr.length))
-                       block += pad_file_size(v, hdr.length) / v->block_size;
-       } while (hdr.type == DATA);
-       block = config_find(v, &conf, &hdr);
-       if (block > 0)
-               fprintf(stderr, "block %d:\tsentinel entry, size: %d, sectors: %d, sequence: %d\n", block, hdr.length, pad_file_size(v, hdr.length) / v->block_size, hdr.seq);
-
-       return 0;
-}
-
-static int
+int
 snapshot_write_file(struct volume *v, int block, char *file, uint32_t seq, uint32_t type)
 {
        uint32_t md5[4] = { 0 };
@@ -266,7 +167,7 @@ out:
        return ret;
 }
 
-static int
+int
 snapshot_read_file(struct volume *v, int block, char *file, uint32_t type)
 {
        struct file_header hdr;
@@ -294,15 +195,18 @@ snapshot_read_file(struct volume *v, int block, char *file, uint32_t type)
                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;
        }
@@ -320,7 +224,7 @@ snapshot_read_file(struct volume *v, int block, char *file, uint32_t type)
        return block;
 }
 
-static int
+int
 sentinel_write(struct volume *v, uint32_t _seq)
 {
        int ret, block;
@@ -348,7 +252,7 @@ sentinel_write(struct volume *v, uint32_t _seq)
        return ret;
 }
 
-static int
+int
 volatile_write(struct volume *v, uint32_t _seq)
 {
        int block, ret;
@@ -369,149 +273,12 @@ volatile_write(struct volume *v, uint32_t _seq)
 }
 
 static int
-config_write(int argc, char **argv)
-{
-       struct volume *v = volume_find("rootfs_data");
-       int ret;
-
-       if (!v)
-               return -1;
-
-       ret = volatile_write(v, 0);
-       if (!ret)
-               ret = sentinel_write(v, 0);
-
-       return ret;
-}
-
-static int
-config_read(int argc, char **argv)
-{
-       struct volume *v = volume_find("rootfs_data");
-       struct file_header conf, sentinel;
-       int next, block, ret = 0;
-       uint32_t seq;
-
-       if (!v)
-               return -1;
-
-       block = config_find(v, &conf, &sentinel);
-       next = snapshot_next_free(v, &seq);
-       if (is_config(&conf) && conf.seq == seq)
-               block = next;
-       else if (!is_config(&sentinel) || sentinel.seq != seq)
-               return -1;
-
-       unlink("/tmp/config.tar.gz");
-       ret = snapshot_read_file(v, block, "/tmp/config.tar.gz", CONF);
-
-       if (ret < 1)
-               fprintf(stderr, "failed to read /tmp/config.tar.gz\n");
-
-       return ret;
-}
-
-static int
-snapshot_write(int argc, char **argv)
-{
-       struct volume *v = volume_find("rootfs_data");
-       int block, ret;
-       uint32_t seq;
-
-       if (!v)
-               return -1;
-
-       block = snapshot_next_free(v, &seq);
-       if (block < 0)
-               block = 0;
-
-       ret = snapshot_write_file(v, block, "/tmp/snapshot.tar.gz", seq + 1, DATA);
-       if (ret)
-               fprintf(stderr, "failed to write /tmp/snapshot.tar.gz\n");
-       else
-               fprintf(stderr, "wrote /tmp/snapshot.tar.gz\n");
-
-       return ret;
-}
-
-static int
-snapshot_mark(int argc, char **argv)
-{
-       __be32 owrt = cpu_to_be32(OWRT);
-       struct volume *v;
-       size_t sz;
-       int fd;
-
-       fprintf(stderr, "This will remove all snapshot data stored on the system. Are you sure? [N/y]\n");
-       if (getchar() != 'y')
-               return -1;
-
-       v = volume_find("rootfs_data");
-       if (!v) {
-               fprintf(stderr, "no rootfs_data was found\n");
-               return -1;
-       }
-
-       fd = open(v->blk, O_WRONLY);
-       fprintf(stderr, "%s - marking with 0x%08x\n", v->blk, owrt);
-       if (fd < 0) {
-               fprintf(stderr, "opening %s failed\n", v->blk);
-               return -1;
-       }
-
-       sz = write(fd, &owrt, sizeof(owrt));
-       close(fd);
-
-       if (sz != 1) {
-               fprintf(stderr, "writing %s failed: %s\n", v->blk, strerror(errno));
-               return -1;
-       }
-
-       return 0;
-}
-
-static int
-snapshot_read(int argc, char **argv)
-{
-       struct volume *v = volume_find("rootfs_data");;
-       int block = 0, ret = 0;
-       char file[64];
-
-       if (!v)
-               return -1;
-
-       if (argc > 1) {
-               block = atoi(argv[1]);
-               if (block >= (v->size / v->block_size)) {
-                       fprintf(stderr, "invalid block %d > %llu\n", block, v->size / v->block_size);
-                       goto out;
-               }
-               snprintf(file, sizeof(file), "/tmp/snapshot/block%d.tar.gz", block);
-
-               ret = snapshot_read_file(v, block, file, DATA);
-               goto out;
-       }
-
-       do {
-               snprintf(file, sizeof(file), "/tmp/snapshot/block%d.tar.gz", block);
-               block = snapshot_read_file(v, block, file, DATA);
-       } while (block > 0);
-
-out:
-       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) {
@@ -556,10 +323,10 @@ _ramoverlay(char *rom, char *overlay)
        return fopivot(overlay, rom);
 }
 
-static int
-snapshot_mount(void)
+int
+mount_snapshot(struct volume *v)
 {
-       snapshot_sync();
+       snapshot_sync(v);
        setenv("SNAPSHOT", "magic", 1);
        _ramoverlay("/rom", "/overlay");
        system("/sbin/snapshot unpack");
@@ -573,30 +340,3 @@ snapshot_mount(void)
        unsetenv("SNAPSHOT");
        return -1;
 }
-
-static struct backend_handler snapshot_handlers[] = {
-{
-       .name = "config_read",
-       .cli = config_read,
-}, {
-       .name = "config_write",
-       .cli = config_write,
-}, {
-       .name = "read",
-       .cli = snapshot_read,
-}, {
-       .name = "write",
-       .cli = snapshot_write,
-}, {
-       .name = "mark",
-       .cli = snapshot_mark,
-}};
-
-static struct backend snapshot_backend = {
-       .name = "snapshot",
-       .num_handlers = ARRAY_SIZE(snapshot_handlers),
-       .handlers = snapshot_handlers,
-       .mount = snapshot_mount,
-       .info = snapshot_info,
-};
-BACKEND(snapshot_backend);