1 /* 2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2.1 6 * as published by the Free Software Foundation 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <sys/stat.h> 15 #include <sys/stat.h> 16 #include <sys/types.h> 17 #include <sys/ioctl.h> 18 #include <sys/mount.h> 19 #include <mtd/mtd-user.h> 20 21 #include <glob.h> 22 #include <fcntl.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <libgen.h> 26 #include <unistd.h> 27 #include <string.h> 28 #include <inttypes.h> 29 30 #include <libubox/list.h> 31 #include <libubox/blob.h> 32 #include <libubox/md5.h> 33 #include <libubox/ulog.h> 34 35 #include "libfstools/libfstools.h" 36 #include "libfstools/volume.h" 37 #include "libfstools/snapshot.h" 38 39 static int 40 config_write(int argc, char **argv) 41 { 42 struct volume *v = volume_find("rootfs_data"); 43 int ret; 44 45 if (!v) 46 return -1; 47 48 volume_init(v); 49 ret = volatile_write(v, 0); 50 if (!ret) 51 ret = sentinel_write(v, 0); 52 53 return ret; 54 } 55 56 static int 57 config_read(int argc, char **argv) 58 { 59 struct volume *v = volume_find("rootfs_data"); 60 struct file_header conf, sentinel; 61 int next, block, ret = 0; 62 uint32_t seq; 63 64 if (!v) 65 return -1; 66 67 volume_init(v); 68 block = config_find(v, &conf, &sentinel); 69 next = snapshot_next_free(v, &seq); 70 if (is_config(&conf) && conf.seq == seq) 71 block = next; 72 else if (!is_config(&sentinel) || sentinel.seq != seq) 73 return -1; 74 75 unlink("/tmp/config.tar.gz"); 76 ret = snapshot_read_file(v, block, "/tmp/config.tar.gz", CONF); 77 78 if (ret < 1) 79 ULOG_ERR("failed to read /tmp/config.tar.gz\n"); 80 81 return ret; 82 } 83 84 static int 85 snapshot_write(int argc, char **argv) 86 { 87 struct volume *v = volume_find("rootfs_data"); 88 int block, ret; 89 uint32_t seq; 90 91 if (!v) 92 return -1; 93 94 volume_init(v); 95 block = snapshot_next_free(v, &seq); 96 if (block < 0) 97 block = 0; 98 99 ret = snapshot_write_file(v, block, "/tmp/snapshot.tar.gz", seq + 1, DATA); 100 if (ret) 101 ULOG_ERR("failed to write /tmp/snapshot.tar.gz\n"); 102 else 103 ULOG_INFO("wrote /tmp/snapshot.tar.gz\n"); 104 105 return ret; 106 } 107 108 static int 109 snapshot_mark(int argc, char **argv) 110 { 111 __be32 owrt = cpu_to_be32(OWRT); 112 struct volume *v; 113 size_t sz; 114 int fd; 115 116 ULOG_WARN("This will remove all snapshot data stored on the system. Are you sure? [N/y]\n"); 117 if (getchar() != 'y') 118 return -1; 119 120 v = volume_find("rootfs_data"); 121 if (!v) { 122 ULOG_ERR("MTD partition 'rootfs_data' not found\n"); 123 return -1; 124 } 125 126 volume_init(v); 127 128 fd = open(v->blk, O_WRONLY); 129 ULOG_INFO("%s - marking with 0x%08x\n", v->blk, owrt); 130 if (fd < 0) { 131 ULOG_ERR("opening %s failed\n", v->blk); 132 return -1; 133 } 134 135 sz = write(fd, &owrt, sizeof(owrt)); 136 close(fd); 137 138 if (sz != 1) { 139 ULOG_ERR("writing %s failed: %m\n", v->blk); 140 return -1; 141 } 142 143 return 0; 144 } 145 146 static int 147 snapshot_read(int argc, char **argv) 148 { 149 struct volume *v = volume_find("rootfs_data");; 150 int block = 0, ret = 0; 151 char file[64]; 152 153 if (!v) 154 return -1; 155 156 volume_init(v); 157 if (argc > 2) { 158 block = atoi(argv[2]); 159 if (block >= (v->size / v->block_size)) { 160 ULOG_ERR("invalid block %d > %" PRIu64 "\n", 161 block, (uint64_t) v->size / v->block_size); 162 goto out; 163 } 164 snprintf(file, sizeof(file), "/tmp/snapshot/block%d.tar.gz", block); 165 166 ret = snapshot_read_file(v, block, file, DATA); 167 goto out; 168 } 169 170 do { 171 snprintf(file, sizeof(file), "/tmp/snapshot/block%d.tar.gz", block); 172 block = snapshot_read_file(v, block, file, DATA); 173 } while (block > 0); 174 175 out: 176 return ret; 177 } 178 179 static int 180 snapshot_info(void) 181 { 182 struct volume *v = volume_find("rootfs_data"); 183 struct file_header hdr = { 0 }, conf; 184 int block = 0; 185 186 if (!v) 187 return -1; 188 189 volume_init(v); 190 ULOG_INFO("sectors:\t%" PRIu64 ", block_size:\t%dK\n", 191 (uint64_t) v->size / v->block_size, v->block_size / 1024); 192 do { 193 if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) { 194 ULOG_ERR("scanning for next free block failed\n"); 195 return 0; 196 } 197 198 be32_to_hdr(&hdr); 199 200 if (hdr.magic != OWRT) 201 break; 202 203 if (hdr.type == DATA) 204 ULOG_INFO("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); 205 else if (hdr.type == CONF) 206 ULOG_INFO("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); 207 208 if (hdr.type == DATA && !valid_file_size(hdr.length)) 209 block += pad_file_size(v, hdr.length) / v->block_size; 210 } while (hdr.type == DATA); 211 block = config_find(v, &conf, &hdr); 212 if (block > 0) 213 ULOG_INFO("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); 214 215 return 0; 216 } 217 218 int main(int argc, char **argv) 219 { 220 if (argc < 2) 221 return -1; 222 223 if (!strcmp(argv[1], "config_read")) 224 return config_read(argc, argv); 225 if (!strcmp(argv[1], "config_write")) 226 return config_write(argc, argv); 227 if (!strcmp(argv[1], "read")) 228 return snapshot_read(argc, argv); 229 if (!strcmp(argv[1], "write")) 230 return snapshot_write(argc, argv); 231 if (!strcmp(argv[1], "mark")) 232 return snapshot_mark(argc, argv); 233 if (!strcmp(argv[1], "info")) 234 return snapshot_info(); 235 return -1; 236 } 237
This page was automatically generated by LXR 0.3.1. • OpenWrt