split snapshot tool properly
authorJohn Crispin <blogic@openwrt.org>
Mon, 7 Apr 2014 10:50:48 +0000 (11:50 +0100)
committerJohn Crispin <blogic@openwrt.org>
Mon, 7 Apr 2014 13:30:09 +0000 (14:30 +0100)
Signed-off-by: John Crispin <blogic@openwrt.org>
libfstools/mtd.c
libfstools/snapshot.c
libfstools/snapshot.h [new file with mode: 0644]
snapshot.c

index 60326fed12a6c0cf20249a1678ff3ce372dcc394..00bb2d6a549398cef21b315493fedd8485e9fc62 100644 (file)
@@ -170,6 +170,11 @@ static int mtd_volume_find(struct volume *v, char *name)
        snprintf(buffer, sizeof(buffer), "/dev/mtd%s", idx);
        p->chr = strdup(buffer);
 
+       if (mtd_volume_load(v)) {
+               fprintf(stderr, "reading %s failed\n", v->name);
+               return -1;
+       }
+
        return 0;
 }
 
@@ -192,7 +197,7 @@ static int mtd_volume_identify(struct volume *v)
                return -1;
        }
 
-       if (deadc0de == 0x4f575254)
+       if (deadc0de == __be32_to_cpu(0x4f575254))
                return FS_SNAPSHOT;
 
        deadc0de = __be32_to_cpu(deadc0de);
index 6fe9c94ef4abc329016d30b1686347ca6b04f8ae..3289a9dc42ebba2dd970c54823c1e1d2dbdd5ecb 100644 (file)
 
 #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,7 +110,7 @@ config_find(struct volume *v, struct file_header *conf, struct file_header *sent
        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 };
@@ -229,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;
@@ -257,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;
        }
@@ -283,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;
@@ -311,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;
diff --git a/libfstools/snapshot.h b/libfstools/snapshot.h
new file mode 100644 (file)
index 0000000..636f004
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SNAPSHOT_H__
+#define _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 inline 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 inline 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 inline 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;
+}
+
+int verify_file_hash(char *file, uint32_t *hash);
+int snapshot_next_free(struct volume *v, uint32_t *seq);
+int config_find(struct volume *v, struct file_header *conf, struct file_header *sentinel);
+int snapshot_write_file(struct volume *v, int block, char *file, uint32_t seq, uint32_t type);
+int snapshot_read_file(struct volume *v, int block, char *file, uint32_t type);
+int sentinel_write(struct volume *v, uint32_t _seq);
+int volatile_write(struct volume *v, uint32_t _seq);
+
+#endif
index 05a6dee577978c2fe63f6e82a66f7f0aaecdde11..e817e699938060bafcef283e6eaad38c24de71dd 100644 (file)
 
 #include "libfstools/libfstools.h"
 #include "libfstools/volume.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
-verify_file_hash(char *file, uint32_t *hash)
-{
-       uint32_t md5[4];
-
-       if (md5sum(file, md5)) {
-               fprintf(stderr, "failed to generate md5 sum\n");
-               return -1;
-       }
-
-       if (memcmp(md5, hash, sizeof(md5))) {
-               fprintf(stderr, "failed to verify hash of %s.\n", file);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int
-snapshot_next_free(struct volume *v, uint32_t *seq)
-{
-       struct file_header hdr = { 0 };
-       int block = 0;
-
-       *seq = rand();
-
-       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 && !valid_file_size(hdr.length)) {
-                       if (*seq + 1 != hdr.seq && block)
-                               return block;
-                       *seq = hdr.seq;
-                       block += pad_file_size(v, hdr.length) / v->block_size;
-               }
-       } while (hdr.type == DATA);
-
-       return block;
-}
+#include "libfstools/snapshot.h"
 
 static int
-config_find(struct volume *v, struct file_header *conf, struct file_header *sentinel)
-{
-       uint32_t seq;
-       int i, next = snapshot_next_free(v, &seq);
-
-       conf->magic = sentinel->magic = 0;
-
-       if (!volume_read(v, conf, next, sizeof(*conf)))
-               be32_to_hdr(conf);
-
-       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");
-                       return -1;
-               }
-               be32_to_hdr(sentinel);
-
-               if (sentinel->magic == OWRT && sentinel->type == CONF && !valid_file_size(sentinel->length)) {
-                       if (next == i)
-                               return -1;
-                       return i;
-               }
-       }
-
-       return -1;
-}
-
-static int
-snapshot_write_file(struct volume *v, int block, char *file, uint32_t seq, uint32_t type)
-{
-       uint32_t md5[4] = { 0 };
-       struct file_header hdr;
-       struct stat s;
-        char buffer[256];
-       int in = 0, len, offset;
-       int ret = -1;
-
-       if (stat(file, &s) || md5sum(file, md5)) {
-               fprintf(stderr, "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");
-               goto out;
-       }
-       volume_erase(v, block * v->block_size, pad_file_size(v, s.st_size));
-       volume_erase(v, block * v->block_size + pad_file_size(v, s.st_size), v->block_size);
-
-       hdr.length = s.st_size;
-       hdr.magic = OWRT;
-       hdr.type = type;
-       hdr.seq = seq;
-       memcpy(hdr.md5, md5, sizeof(md5));
-       hdr_to_be32(&hdr);
-
-       if (volume_write(v, &hdr, block * v->block_size, sizeof(struct file_header))) {
-               fprintf(stderr, "failed to write header\n");
-               goto out;
-       }
-
-       in = open(file, O_RDONLY);
-       if (in < 1) {
-               fprintf(stderr, "failed to open %s\n", file);
-               goto out;
-       }
-
-       offset = (block * v->block_size) + sizeof(struct file_header);
-
-       while ((len = read(in, buffer, sizeof(buffer))) > 0) {
-               if (volume_write(v, buffer, offset, len) < 0)
-                       goto out;
-               offset += len;
-       }
-
-       ret = 0;
-
-out:
-       if (in > 0)
-               close(in);
-
-       return ret;
-}
-
-static int
-snapshot_read_file(struct volume *v, int block, char *file, uint32_t type)
-{
-       struct file_header hdr;
-       char buffer[256];
-       int out, offset = 0;
-
-       if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) {
-               fprintf(stderr, "failed to read header\n");
-               return -1;
-       }
-       be32_to_hdr(&hdr);
-
-       if (hdr.magic != OWRT)
-               return -1;
-
-       if (hdr.type != type)
-               return -1;
-
-       if (valid_file_size(hdr.length))
-               return -1;
-
-       out = open(file, O_WRONLY | O_CREAT, 0700);
-       if (!out) {
-               fprintf(stderr, "failed to open %s\n", file);
-               return -1;
-       }
-
-       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))
-                       return -1;
-
-               offset += len;
-               hdr.length -= len;
-       }
-
-       close(out);
-
-       if (verify_file_hash(file, hdr.md5)) {
-               fprintf(stderr, "md5 verification failed\n");
-               unlink(file);
-               return 0;
-       }
-
-        block += pad_file_size(v, hdr.length) / v->block_size;
-
-       return block;
-}
-
-static int
-sentinel_write(struct volume *v, uint32_t _seq)
-{
-       int ret, block;
-       struct stat s;
-       uint32_t seq;
-
-       if (stat("/tmp/config.tar.gz", &s)) {
-               fprintf(stderr, "failed to stat /tmp/config.tar.gz\n");
-               return -1;
-       }
-
-       snapshot_next_free(v, &seq);
-       if (_seq)
-               seq = _seq;
-       block = v->size / v->block_size;
-       block -= pad_file_size(v, s.st_size) / v->block_size;
-       if (block < 0)
-               block = 0;
-
-       ret = snapshot_write_file(v, block, "/tmp/config.tar.gz", seq, CONF);
-       if (ret)
-               fprintf(stderr, "failed to write sentinel\n");
-       else
-               fprintf(stderr, "wrote /tmp/config.tar.gz sentinel\n");
-       return ret;
-}
-
-static int
-volatile_write(struct volume *v, uint32_t _seq)
-{
-       int block, ret;
-       uint32_t seq;
-
-       block = snapshot_next_free(v, &seq);
-       if (_seq)
-               seq = _seq;
-       if (block < 0)
-               block = 0;
-
-       ret = snapshot_write_file(v, block, "/tmp/config.tar.gz", seq, CONF);
-       if (ret)
-               fprintf(stderr, "failed to write /tmp/config.tar.gz\n");
-       else
-               fprintf(stderr, "wrote /tmp/config.tar.gz\n");
-       return ret;
-}
-
-static int
-config_write(int argc, char *argv[1])
+config_write(int argc, char **argv)
 {
        struct volume *v = volume_find("rootfs_data");
        int ret;
@@ -348,7 +51,7 @@ config_write(int argc, char *argv[1])
 }
 
 static int
-config_read(int argc, char *argv[1])
+config_read(int argc, char **argv)
 {
        struct volume *v = volume_find("rootfs_data");
        struct file_header conf, sentinel;
@@ -375,7 +78,7 @@ config_read(int argc, char *argv[1])
 }
 
 static int
-snapshot_write(int argc, char *argv[1])
+snapshot_write(int argc, char **argv)
 {
        struct volume *v = volume_find("rootfs_data");
        int block, ret;
@@ -398,7 +101,7 @@ snapshot_write(int argc, char *argv[1])
 }
 
 static int
-snapshot_mark(int argc, char *argv[1])
+snapshot_mark(int argc, char **argv)
 {
        __be32 owrt = cpu_to_be32(OWRT);
        struct volume *v;
@@ -434,7 +137,7 @@ snapshot_mark(int argc, char *argv[1])
 }
 
 static int
-snapshot_read(int argc, char *argv[1])
+snapshot_read(int argc, char **argv)
 {
        struct volume *v = volume_find("rootfs_data");;
        int block = 0, ret = 0;
@@ -443,8 +146,8 @@ snapshot_read(int argc, char *argv[1])
        if (!v)
                return -1;
 
-       if (argc > 1) {
-               block = atoi(argv[1]);
+       if (argc > 2) {
+               block = atoi(argv[2]);
                if (block >= (v->size / v->block_size)) {
                        fprintf(stderr, "invalid block %d > %llu\n", block, v->size / v->block_size);
                        goto out;
@@ -464,6 +167,43 @@ out:
        return ret;
 }
 
+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;
+}
+
 int main(int argc, char **argv)
 {
        if (argc < 2)
@@ -479,5 +219,7 @@ int main(int argc, char **argv)
                return snapshot_write(argc, argv);
        if (!strcmp(argv[1], "mark"))
                return snapshot_mark(argc, argv);
+       if (!strcmp(argv[1], "info"))
+               return snapshot_info();
        return -1;
 }