snapshot.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. #include <sys/stat.h>
  14. #include <sys/stat.h>
  15. #include <sys/types.h>
  16. #include <sys/ioctl.h>
  17. #include <sys/mount.h>
  18. #include <mtd/mtd-user.h>
  19. #include <glob.h>
  20. #include <fcntl.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <libgen.h>
  24. #include <unistd.h>
  25. #include <string.h>
  26. #include <inttypes.h>
  27. #include <libubox/list.h>
  28. #include <libubox/blob.h>
  29. #include <libubox/md5.h>
  30. #include <libubox/ulog.h>
  31. #include "libfstools/libfstools.h"
  32. #include "libfstools/volume.h"
  33. #include "libfstools/snapshot.h"
  34. static int
  35. config_write(int argc, char **argv)
  36. {
  37. struct volume *v = volume_find("rootfs_data");
  38. int ret;
  39. if (!v)
  40. return -1;
  41. volume_init(v);
  42. ret = volatile_write(v, 0);
  43. if (!ret)
  44. ret = sentinel_write(v, 0);
  45. return ret;
  46. }
  47. static int
  48. config_read(int argc, char **argv)
  49. {
  50. struct volume *v = volume_find("rootfs_data");
  51. struct file_header conf, sentinel;
  52. int next, block, ret = 0;
  53. uint32_t seq;
  54. if (!v)
  55. return -1;
  56. volume_init(v);
  57. block = config_find(v, &conf, &sentinel);
  58. next = snapshot_next_free(v, &seq);
  59. if (is_config(&conf) && conf.seq == seq)
  60. block = next;
  61. else if (!is_config(&sentinel) || sentinel.seq != seq)
  62. return -1;
  63. unlink("/tmp/config.tar.gz");
  64. ret = snapshot_read_file(v, block, "/tmp/config.tar.gz", CONF);
  65. if (ret < 1)
  66. ULOG_ERR("failed to read /tmp/config.tar.gz\n");
  67. return ret;
  68. }
  69. static int
  70. snapshot_write(int argc, char **argv)
  71. {
  72. struct volume *v = volume_find("rootfs_data");
  73. int block, ret;
  74. uint32_t seq;
  75. if (!v)
  76. return -1;
  77. volume_init(v);
  78. block = snapshot_next_free(v, &seq);
  79. if (block < 0)
  80. block = 0;
  81. ret = snapshot_write_file(v, block, "/tmp/snapshot.tar.gz", seq + 1, DATA);
  82. if (ret)
  83. ULOG_ERR("failed to write /tmp/snapshot.tar.gz\n");
  84. else
  85. ULOG_INFO("wrote /tmp/snapshot.tar.gz\n");
  86. return ret;
  87. }
  88. static int
  89. snapshot_mark(int argc, char **argv)
  90. {
  91. __be32 owrt = cpu_to_be32(OWRT);
  92. struct volume *v;
  93. size_t sz;
  94. int fd;
  95. ULOG_WARN("This will remove all snapshot data stored on the system. Are you sure? [N/y]\n");
  96. if (getchar() != 'y')
  97. return -1;
  98. v = volume_find("rootfs_data");
  99. if (!v) {
  100. ULOG_ERR("MTD partition 'rootfs_data' not found\n");
  101. return -1;
  102. }
  103. volume_init(v);
  104. fd = open(v->blk, O_WRONLY);
  105. ULOG_INFO("%s - marking with 0x%08x\n", v->blk, owrt);
  106. if (fd < 0) {
  107. ULOG_ERR("opening %s failed\n", v->blk);
  108. return -1;
  109. }
  110. sz = write(fd, &owrt, sizeof(owrt));
  111. close(fd);
  112. if (sz != 1) {
  113. ULOG_ERR("writing %s failed: %m\n", v->blk);
  114. return -1;
  115. }
  116. return 0;
  117. }
  118. static int
  119. snapshot_read(int argc, char **argv)
  120. {
  121. struct volume *v = volume_find("rootfs_data");;
  122. int block = 0, ret = 0;
  123. char file[64];
  124. if (!v)
  125. return -1;
  126. volume_init(v);
  127. if (argc > 2) {
  128. block = atoi(argv[2]);
  129. if (block >= (v->size / v->block_size)) {
  130. ULOG_ERR("invalid block %d > %" PRIu64 "\n",
  131. block, (uint64_t) v->size / v->block_size);
  132. goto out;
  133. }
  134. snprintf(file, sizeof(file), "/tmp/snapshot/block%d.tar.gz", block);
  135. ret = snapshot_read_file(v, block, file, DATA);
  136. goto out;
  137. }
  138. do {
  139. snprintf(file, sizeof(file), "/tmp/snapshot/block%d.tar.gz", block);
  140. block = snapshot_read_file(v, block, file, DATA);
  141. } while (block > 0);
  142. out:
  143. return ret;
  144. }
  145. static int
  146. snapshot_info(void)
  147. {
  148. struct volume *v = volume_find("rootfs_data");
  149. struct file_header hdr = { 0 }, conf;
  150. int block = 0;
  151. if (!v)
  152. return -1;
  153. volume_init(v);
  154. ULOG_INFO("sectors:\t%" PRIu64 ", block_size:\t%dK\n",
  155. (uint64_t) v->size / v->block_size, v->block_size / 1024);
  156. do {
  157. if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) {
  158. ULOG_ERR("scanning for next free block failed\n");
  159. return 0;
  160. }
  161. be32_to_hdr(&hdr);
  162. if (hdr.magic != OWRT)
  163. break;
  164. if (hdr.type == DATA)
  165. 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);
  166. else if (hdr.type == CONF)
  167. 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);
  168. if (hdr.type == DATA && !valid_file_size(hdr.length))
  169. block += pad_file_size(v, hdr.length) / v->block_size;
  170. } while (hdr.type == DATA);
  171. block = config_find(v, &conf, &hdr);
  172. if (block > 0)
  173. 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);
  174. return 0;
  175. }
  176. int main(int argc, char **argv)
  177. {
  178. if (argc < 2)
  179. return -1;
  180. if (!strcmp(argv[1], "config_read"))
  181. return config_read(argc, argv);
  182. if (!strcmp(argv[1], "config_write"))
  183. return config_write(argc, argv);
  184. if (!strcmp(argv[1], "read"))
  185. return snapshot_read(argc, argv);
  186. if (!strcmp(argv[1], "write"))
  187. return snapshot_write(argc, argv);
  188. if (!strcmp(argv[1], "mark"))
  189. return snapshot_mark(argc, argv);
  190. if (!strcmp(argv[1], "info"))
  191. return snapshot_info();
  192. return -1;
  193. }