From: John Crispin Date: Mon, 7 Apr 2014 10:50:48 +0000 (+0100) Subject: split snapshot tool properly X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffstools.git;a=commitdiff_plain;h=a1f48fc0444f5c3c44ee6ef1005cd8da65decefd split snapshot tool properly Signed-off-by: John Crispin --- diff --git a/libfstools/mtd.c b/libfstools/mtd.c index 60326fe..00bb2d6 100644 --- a/libfstools/mtd.c +++ b/libfstools/mtd.c @@ -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); diff --git a/libfstools/snapshot.c b/libfstools/snapshot.c index 6fe9c94..3289a9d 100644 --- a/libfstools/snapshot.c +++ b/libfstools/snapshot.c @@ -32,71 +32,9 @@ #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 index 0000000..636f004 --- /dev/null +++ b/libfstools/snapshot.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 John Crispin + * + * 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 diff --git a/snapshot.c b/snapshot.c index 05a6dee..e817e69 100644 --- a/snapshot.c +++ b/snapshot.c @@ -32,307 +32,10 @@ #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; }