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 29 #include <libubox/list.h> 30 #include <libubox/blob.h> 31 #include <libubox/md5.h> 32 33 #include "libfstools.h" 34 #include "volume.h" 35 #include "snapshot.h" 36 37 int 38 verify_file_hash(char *file, uint32_t *hash) 39 { 40 uint32_t md5[4]; 41 42 if (md5sum(file, md5) <= 0) { 43 ULOG_ERR("failed to generate md5 sum\n"); 44 return -1; 45 } 46 47 if (memcmp(md5, hash, sizeof(md5))) { 48 ULOG_ERR("failed to verify hash of %s.\n", file); 49 return -1; 50 } 51 52 return 0; 53 } 54 55 int 56 snapshot_next_free(struct volume *v, uint32_t *seq) 57 { 58 struct file_header hdr = { 0 }; 59 int block = 0; 60 61 *seq = rand(); 62 63 do { 64 if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) { 65 ULOG_ERR("scanning for next free block failed\n"); 66 return 0; 67 } 68 69 be32_to_hdr(&hdr); 70 71 if (hdr.magic != OWRT) 72 break; 73 74 if (hdr.type == DATA && !valid_file_size(hdr.length)) { 75 if (*seq + 1 != hdr.seq && block) 76 return block; 77 *seq = hdr.seq; 78 block += pad_file_size(v, hdr.length) / v->block_size; 79 } 80 } while (hdr.type == DATA); 81 82 return block; 83 } 84 85 int 86 config_find(struct volume *v, struct file_header *conf, struct file_header *sentinel) 87 { 88 uint32_t seq; 89 int i, next = snapshot_next_free(v, &seq); 90 91 conf->magic = sentinel->magic = 0; 92 93 if (!volume_read(v, conf, next, sizeof(*conf))) 94 be32_to_hdr(conf); 95 96 for (i = (v->size / v->block_size) - 1; i > 0; i--) { 97 if (volume_read(v, sentinel, i * v->block_size, sizeof(*sentinel))) { 98 ULOG_ERR("failed to read header\n"); 99 return -1; 100 } 101 be32_to_hdr(sentinel); 102 103 if (sentinel->magic == OWRT && sentinel->type == CONF && !valid_file_size(sentinel->length)) { 104 if (next == i) 105 return -1; 106 return i; 107 } 108 } 109 110 return -1; 111 } 112 113 int 114 snapshot_write_file(struct volume *v, int block, char *file, uint32_t seq, uint32_t type) 115 { 116 uint32_t md5[4] = { 0 }; 117 struct file_header hdr; 118 struct stat s; 119 char buffer[256]; 120 int in = 0, len, offset; 121 int ret = -1; 122 123 if (stat(file, &s) || md5sum(file, md5) != s.st_size) { 124 ULOG_ERR("stat failed on %s\n", file); 125 goto out; 126 } 127 128 if ((block * v->block_size) + pad_file_size(v, s.st_size) > v->size) { 129 ULOG_ERR("upgrade is too big for the flash\n"); 130 goto out; 131 } 132 volume_erase(v, block * v->block_size, pad_file_size(v, s.st_size)); 133 volume_erase(v, block * v->block_size + pad_file_size(v, s.st_size), v->block_size); 134 135 hdr.length = s.st_size; 136 hdr.magic = OWRT; 137 hdr.type = type; 138 hdr.seq = seq; 139 memcpy(hdr.md5, md5, sizeof(md5)); 140 hdr_to_be32(&hdr); 141 142 if (volume_write(v, &hdr, block * v->block_size, sizeof(struct file_header))) { 143 ULOG_ERR("failed to write header\n"); 144 goto out; 145 } 146 147 in = open(file, O_RDONLY); 148 if (in < 0) { 149 ULOG_ERR("failed to open %s\n", file); 150 goto out; 151 } 152 153 offset = (block * v->block_size) + sizeof(struct file_header); 154 155 while ((len = read(in, buffer, sizeof(buffer))) > 0) { 156 if (volume_write(v, buffer, offset, len) < 0) 157 goto out; 158 offset += len; 159 } 160 161 ret = 0; 162 163 out: 164 if (in >= 0) 165 close(in); 166 167 return ret; 168 } 169 170 int 171 snapshot_read_file(struct volume *v, int block, char *file, uint32_t type) 172 { 173 struct file_header hdr; 174 char buffer[256]; 175 int out, offset = 0; 176 177 if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) { 178 ULOG_ERR("failed to read header\n"); 179 return -1; 180 } 181 be32_to_hdr(&hdr); 182 183 if (hdr.magic != OWRT) 184 return -1; 185 186 if (hdr.type != type) 187 return -1; 188 189 if (valid_file_size(hdr.length)) 190 return -1; 191 192 out = open(file, O_WRONLY | O_CREAT, 0700); 193 if (out < 0) { 194 ULOG_ERR("failed to open %s\n", file); 195 return -1; 196 } 197 198 offset = block * v->block_size + sizeof(hdr); 199 200 while (hdr.length > 0) { 201 int len = sizeof(buffer); 202 203 if (hdr.length < len) 204 len = hdr.length; 205 206 if (volume_read(v, buffer, offset, len)) { 207 close(out); 208 return -1; 209 } 210 if (write(out, buffer, len) != len) { 211 close(out); 212 return -1; 213 } 214 offset += len; 215 hdr.length -= len; 216 } 217 218 close(out); 219 220 if (verify_file_hash(file, hdr.md5)) { 221 ULOG_ERR("md5 verification failed\n"); 222 unlink(file); 223 return 0; 224 } 225 226 block += pad_file_size(v, hdr.length) / v->block_size; 227 228 return block; 229 } 230 231 int 232 sentinel_write(struct volume *v, uint32_t _seq) 233 { 234 int ret, block; 235 struct stat s; 236 uint32_t seq; 237 238 if (stat("/tmp/config.tar.gz", &s)) { 239 ULOG_ERR("failed to stat /tmp/config.tar.gz\n"); 240 return -1; 241 } 242 243 snapshot_next_free(v, &seq); 244 if (_seq) 245 seq = _seq; 246 block = v->size / v->block_size; 247 block -= pad_file_size(v, s.st_size) / v->block_size; 248 if (block < 0) 249 block = 0; 250 251 ret = snapshot_write_file(v, block, "/tmp/config.tar.gz", seq, CONF); 252 if (ret) 253 ULOG_ERR("failed to write sentinel\n"); 254 else 255 ULOG_INFO("wrote /tmp/config.tar.gz sentinel\n"); 256 return ret; 257 } 258 259 int 260 volatile_write(struct volume *v, uint32_t _seq) 261 { 262 int block, ret; 263 uint32_t seq; 264 265 block = snapshot_next_free(v, &seq); 266 if (_seq) 267 seq = _seq; 268 if (block < 0) 269 block = 0; 270 271 ret = snapshot_write_file(v, block, "/tmp/config.tar.gz", seq, CONF); 272 if (ret) 273 ULOG_ERR("failed to write /tmp/config.tar.gz\n"); 274 else 275 ULOG_INFO("wrote /tmp/config.tar.gz\n"); 276 return ret; 277 } 278 279 static int 280 snapshot_sync(struct volume *v) 281 { 282 struct file_header sentinel, conf; 283 int next, block = 0; 284 uint32_t seq; 285 286 next = snapshot_next_free(v, &seq); 287 block = config_find(v, &conf, &sentinel); 288 if (is_config(&conf) && conf.seq != seq) { 289 conf.magic = 0; 290 volume_erase(v, next * v->block_size, 2 * v->block_size); 291 } 292 293 if (is_config(&sentinel) && (sentinel.seq != seq)) { 294 sentinel.magic = 0; 295 volume_erase(v, block * v->block_size, v->block_size); 296 } 297 298 if (!is_config(&conf) && !is_config(&sentinel)) { 299 // ULOG_ERR("no config found\n"); 300 } else if (((is_config(&conf) && is_config(&sentinel)) && 301 (memcmp(conf.md5, sentinel.md5, sizeof(conf.md5)) || (conf.seq != sentinel.seq))) || 302 (is_config(&conf) && !is_config(&sentinel))) { 303 uint32_t seq; 304 int next = snapshot_next_free(v, &seq); 305 int ret = snapshot_read_file(v, next, "/tmp/config.tar.gz", CONF); 306 if (ret > 0) { 307 if (sentinel_write(v, conf.seq)) 308 ULOG_ERR("failed to write sentinel data"); 309 } 310 } else if (!is_config(&conf) && is_config(&sentinel) && next) { 311 int ret = snapshot_read_file(v, block, "/tmp/config.tar.gz", CONF); 312 if (ret > 0) 313 if (volatile_write(v, sentinel.seq)) 314 ULOG_ERR("failed to write sentinel data"); 315 } else 316 ULOG_INFO("config in sync\n"); 317 318 unlink("/tmp/config.tar.gz"); 319 320 return 0; 321 } 322 323 static int 324 _ramoverlay(char *rom, char *overlay) 325 { 326 mount("tmpfs", overlay, "tmpfs", MS_NOATIME, "mode=0755"); 327 return fopivot(overlay, rom); 328 } 329 330 int 331 mount_snapshot(struct volume *v) 332 { 333 snapshot_sync(v); 334 setenv("SNAPSHOT", "magic", 1); 335 _ramoverlay("/rom", "/overlay"); 336 if (system("/sbin/snapshot unpack") == -1) { 337 perror("system"); 338 return -1; 339 } 340 foreachdir("/overlay/", handle_whiteout); 341 if (mkdir("/volatile", 0700) == -1 && errno != EEXIST) { 342 perror("mkdir"); 343 return -1; 344 } 345 _ramoverlay("/rom", "/volatile"); 346 mount_move("/rom/volatile", "/volatile", ""); 347 mount_move("/rom/rom", "/rom", ""); 348 if (system("/sbin/snapshot config_unpack")) { 349 perror("system"); 350 return -1; 351 } 352 foreachdir("/volatile/", handle_whiteout); 353 unsetenv("SNAPSHOT"); 354 return -1; 355 } 356
This page was automatically generated by LXR 0.3.1. • OpenWrt