block: support builtin fstab config
[project/fstools.git] / snapshot.c
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
34 #include "libfstools/libfstools.h"
35 #include "libfstools/volume.h"
36 #include "libfstools/snapshot.h"
37
38 static int
39 config_write(int argc, char **argv)
40 {
41         struct volume *v = volume_find("rootfs_data");
42         int ret;
43
44         if (!v)
45                 return -1;
46
47         ret = volatile_write(v, 0);
48         if (!ret)
49                 ret = sentinel_write(v, 0);
50
51         return ret;
52 }
53
54 static int
55 config_read(int argc, char **argv)
56 {
57         struct volume *v = volume_find("rootfs_data");
58         struct file_header conf, sentinel;
59         int next, block, ret = 0;
60         uint32_t seq;
61
62         if (!v)
63                 return -1;
64
65         block = config_find(v, &conf, &sentinel);
66         next = snapshot_next_free(v, &seq);
67         if (is_config(&conf) && conf.seq == seq)
68                 block = next;
69         else if (!is_config(&sentinel) || sentinel.seq != seq)
70                 return -1;
71
72         unlink("/tmp/config.tar.gz");
73         ret = snapshot_read_file(v, block, "/tmp/config.tar.gz", CONF);
74
75         if (ret < 1)
76                 fprintf(stderr, "failed to read /tmp/config.tar.gz\n");
77
78         return ret;
79 }
80
81 static int
82 snapshot_write(int argc, char **argv)
83 {
84         struct volume *v = volume_find("rootfs_data");
85         int block, ret;
86         uint32_t seq;
87
88         if (!v)
89                 return -1;
90
91         block = snapshot_next_free(v, &seq);
92         if (block < 0)
93                 block = 0;
94
95         ret = snapshot_write_file(v, block, "/tmp/snapshot.tar.gz", seq + 1, DATA);
96         if (ret)
97                 fprintf(stderr, "failed to write /tmp/snapshot.tar.gz\n");
98         else
99                 fprintf(stderr, "wrote /tmp/snapshot.tar.gz\n");
100
101         return ret;
102 }
103
104 static int
105 snapshot_mark(int argc, char **argv)
106 {
107         __be32 owrt = cpu_to_be32(OWRT);
108         struct volume *v;
109         size_t sz;
110         int fd;
111
112         fprintf(stderr, "This will remove all snapshot data stored on the system. Are you sure? [N/y]\n");
113         if (getchar() != 'y')
114                 return -1;
115
116         v = volume_find("rootfs_data");
117         if (!v) {
118                 fprintf(stderr, "no rootfs_data was found\n");
119                 return -1;
120         }
121
122         fd = open(v->blk, O_WRONLY);
123         fprintf(stderr, "%s - marking with 0x%08x\n", v->blk, owrt);
124         if (fd < 0) {
125                 fprintf(stderr, "opening %s failed\n", v->blk);
126                 return -1;
127         }
128
129         sz = write(fd, &owrt, sizeof(owrt));
130         close(fd);
131
132         if (sz != 1) {
133                 fprintf(stderr, "writing %s failed: %s\n", v->blk, strerror(errno));
134                 return -1;
135         }
136
137         return 0;
138 }
139
140 static int
141 snapshot_read(int argc, char **argv)
142 {
143         struct volume *v = volume_find("rootfs_data");;
144         int block = 0, ret = 0;
145         char file[64];
146
147         if (!v)
148                 return -1;
149
150         if (argc > 2) {
151                 block = atoi(argv[2]);
152                 if (block >= (v->size / v->block_size)) {
153                         fprintf(stderr, "invalid block %d > %" PRIu64 "\n",
154                                 block, (uint64_t) v->size / v->block_size);
155                         goto out;
156                 }
157                 snprintf(file, sizeof(file), "/tmp/snapshot/block%d.tar.gz", block);
158
159                 ret = snapshot_read_file(v, block, file, DATA);
160                 goto out;
161         }
162
163         do {
164                 snprintf(file, sizeof(file), "/tmp/snapshot/block%d.tar.gz", block);
165                 block = snapshot_read_file(v, block, file, DATA);
166         } while (block > 0);
167
168 out:
169         return ret;
170 }
171
172 static int
173 snapshot_info(void)
174 {
175         struct volume *v = volume_find("rootfs_data");
176         struct file_header hdr = { 0 }, conf;
177         int block = 0;
178
179         if (!v)
180                 return -1;
181
182         fprintf(stderr, "sectors:\t%" PRIu64 ", block_size:\t%dK\n",
183                 (uint64_t) v->size / v->block_size, v->block_size / 1024);
184         do {
185                 if (volume_read(v, &hdr, block * v->block_size, sizeof(struct file_header))) {
186                         fprintf(stderr, "scanning for next free block failed\n");
187                         return 0;
188                 }
189
190                 be32_to_hdr(&hdr);
191
192                 if (hdr.magic != OWRT)
193                         break;
194
195                 if (hdr.type == DATA)
196                         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);
197                 else if (hdr.type == CONF)
198                         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);
199
200                 if (hdr.type == DATA && !valid_file_size(hdr.length))
201                         block += pad_file_size(v, hdr.length) / v->block_size;
202         } while (hdr.type == DATA);
203         block = config_find(v, &conf, &hdr);
204         if (block > 0)
205                 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);
206
207         return 0;
208 }
209
210 int main(int argc, char **argv)
211 {
212         if (argc < 2)
213                 return -1;
214
215         if (!strcmp(argv[1], "config_read"))
216                 return config_read(argc, argv);
217         if (!strcmp(argv[1], "config_write"))
218                 return config_write(argc, argv);
219         if (!strcmp(argv[1], "read"))
220                 return snapshot_read(argc, argv);
221         if (!strcmp(argv[1], "write"))
222                 return snapshot_write(argc, argv);
223         if (!strcmp(argv[1], "mark"))
224                 return snapshot_mark(argc, argv);
225         if (!strcmp(argv[1], "info"))
226                 return snapshot_info();
227         return -1;
228 }