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