blob: 96b8d572fae21a3ff227134f1b0a1d4179be64aa [file] [log] [blame]
Tom Marshallc575fc42015-11-16 13:48:28 -08001/*
2 * Copyright (C) 2019 The LineageOS Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdarg.h>
18#include <stdio.h>
19#include <stdlib.h>
20
21#include <dirent.h>
22#include <fcntl.h>
23#include <sys/socket.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/vfs.h>
27#include <unistd.h>
28
29#include <cutils/log.h>
30#include <cutils/properties.h>
31
32#include <selinux/label.h>
33
34#include <fs_mgr.h>
35#include "roots.h"
36
37#include "bu.h"
38
39#define PATHNAME_RC "/tmp/burc"
40
41using namespace std;
42
43using namespace android;
44
45struct selabel_handle* sehandle;
46
47int adb_ifd;
48int adb_ofd;
49TAR* tar;
50gzFile gzf;
51
52char* hash_name;
53size_t hash_datalen;
54SHA_CTX sha_ctx;
55MD5_CTX md5_ctx;
56
57void ui_print(const char* format, ...) {
58 char buffer[256];
59
60 va_list ap;
61 va_start(ap, format);
62 vsnprintf(buffer, sizeof(buffer), format, ap);
63 va_end(ap);
64
65 fputs(buffer, stdout);
66}
67
68void logmsg(const char* fmt, ...) {
69 char msg[1024];
70 FILE* fp;
71 va_list ap;
72
73 va_start(ap, fmt);
74 vsnprintf(msg, sizeof(msg), fmt, ap);
75 va_end(ap);
76
77 fp = fopen("/tmp/bu.log", "a");
78 if (fp) {
79 fprintf(fp, "[%d] %s", getpid(), msg);
80 fclose(fp);
81 }
82}
83
84static partspec partlist[MAX_PART];
85static partspec* curpart;
86
87int part_add(const char* name) {
88 Volume* vol = NULL;
89 char* path = NULL;
90 int i;
91
92 path = (char*)malloc(1 + strlen(name) + 1);
93 sprintf(path, "/%s", name);
94 vol = volume_for_mount_point(path);
95 if (vol == NULL || vol->fs_type == NULL) {
96 logmsg("missing vol info for %s, ignoring\n", name);
97 goto err;
98 }
99
100 for (i = 0; i < MAX_PART; ++i) {
101 if (partlist[i].name == NULL) {
102 partlist[i].name = strdup(name);
103 partlist[i].path = path;
104 partlist[i].vol = vol;
105 logmsg("part_add: i=%d, name=%s, path=%s\n", i, name, path);
106 return 0;
107 }
108 if (strcmp(partlist[i].name, name) == 0) {
109 logmsg("duplicate partition %s, ignoring\n", name);
110 goto err;
111 }
112 }
113
114err:
115 free(path);
116 return -1;
117}
118
119partspec* part_get(int i) {
120 if (i >= 0 && i < MAX_PART) {
121 if (partlist[i].name != NULL) {
122 return &partlist[i];
123 }
124 }
125 return NULL;
126}
127
128partspec* part_find(const char* name) {
129 for (int i = 0; i < MAX_PART; ++i) {
130 if (partlist[i].name && !strcmp(name, partlist[i].name)) {
131 return &partlist[i];
132 }
133 }
134 return NULL;
135}
136
137void part_set(partspec* part) {
138 curpart = part;
139 curpart->off = 0;
140}
141
142int update_progress(uint64_t off) {
143 static time_t last_time = 0;
144 static int last_pct = 0;
145 if (curpart) {
146 curpart->off += off;
147 time_t now = time(NULL);
148 int pct = min(100, (int)((uint64_t)100 * curpart->off / curpart->used));
149 if (now != last_time && pct != last_pct) {
150 char msg[256];
151 sprintf(msg, "%s: %d%% complete", curpart->name, pct);
152 ui_print(msg);
153 last_time = now;
154 last_pct = pct;
155 }
156 }
157 return 0;
158}
159
160static int tar_cb_open(const char* path, int mode, ...) {
161 errno = EINVAL;
162 return -1;
163}
164
165static int tar_cb_close(int fd) {
166 return 0;
167}
168
169static ssize_t tar_cb_read(int fd, void* buf, size_t len) {
170 ssize_t nread;
171 nread = ::read(fd, buf, len);
172 if (nread > 0 && hash_name) {
173 SHA1_Update(&sha_ctx, (u_char*)buf, nread);
174 MD5_Update(&md5_ctx, buf, nread);
175 hash_datalen += nread;
176 }
177 update_progress(nread);
178 return nread;
179}
180
181static ssize_t tar_cb_write(int fd, const void* buf, size_t len) {
182 ssize_t written = 0;
183
184 if (hash_name) {
185 SHA1_Update(&sha_ctx, (u_char*)buf, len);
186 MD5_Update(&md5_ctx, buf, len);
187 hash_datalen += len;
188 }
189
190 while (len > 0) {
191 ssize_t n = ::write(fd, buf, len);
192 if (n < 0) {
193 logmsg("tar_cb_write: error: n=%d\n", n);
194 return n;
195 }
196 if (n == 0) break;
197 buf = (const char*)buf + n;
198 len -= n;
199 written += n;
200 }
201 update_progress(written);
202 return written;
203}
204
205static tartype_t tar_io = { tar_cb_open, tar_cb_close, tar_cb_read, tar_cb_write };
206
207static ssize_t tar_gz_cb_read(int fd, void* buf, size_t len) {
208 int nread;
209 nread = gzread(gzf, buf, len);
210 if (nread > 0 && hash_name) {
211 SHA1_Update(&sha_ctx, (u_char*)buf, nread);
212 MD5_Update(&md5_ctx, buf, nread);
213 hash_datalen += nread;
214 }
215 update_progress(nread);
216 return nread;
217}
218
219static ssize_t tar_gz_cb_write(int fd, const void* buf, size_t len) {
220 ssize_t written = 0;
221
222 if (hash_name) {
223 SHA1_Update(&sha_ctx, (u_char*)buf, len);
224 MD5_Update(&md5_ctx, buf, len);
225 hash_datalen += len;
226 }
227
228 while (len > 0) {
229 ssize_t n = gzwrite(gzf, buf, len);
230 if (n < 0) {
231 logmsg("tar_gz_cb_write: error: n=%d\n", n);
232 return n;
233 }
234 if (n == 0) break;
235 buf = (const char*)buf + n;
236 len -= n;
237 written += n;
238 }
239 update_progress(written);
240 return written;
241}
242
243static tartype_t tar_io_gz = { tar_cb_open, tar_cb_close, tar_gz_cb_read, tar_gz_cb_write };
244
245int create_tar(int fd, const char* compress, const char* mode) {
246 int rc = -1;
247
248 SHA1_Init(&sha_ctx);
249 MD5_Init(&md5_ctx);
250
251 if (!compress || strcasecmp(compress, "none") == 0) {
252 rc = tar_fdopen(&tar, fd, "foobar", &tar_io, 0, /* oflags: unused */
253 0, /* mode: unused */
254 TAR_GNU | TAR_STORE_SELINUX /* options */);
255 } else if (strcasecmp(compress, "gzip") == 0) {
256 gzf = gzdopen(fd, mode);
257 if (gzf != NULL) {
258 rc = tar_fdopen(&tar, 0, "foobar", &tar_io_gz, 0, /* oflags: unused */
259 0, /* mode: unused */
260 TAR_GNU | TAR_STORE_SELINUX /* options */);
261 }
262 }
263 return rc;
264}
265
266static void do_exit(int rc) {
267 char rcstr[80];
268 int len;
269 len = sprintf(rcstr, "%d\n", rc);
270
271 unlink(PATHNAME_RC);
272 int fd = open(PATHNAME_RC, O_RDWR | O_CREAT, 0644);
273 write(fd, rcstr, len);
274 close(fd);
275 exit(rc);
276}
277
278int main(int argc, char** argv) {
279 int rc = 1;
280
281 const char* logfile = "/tmp/recovery.log";
282 adb_ifd = dup(STDIN_FILENO);
283 adb_ofd = dup(STDOUT_FILENO);
284 freopen(logfile, "a", stdout);
285 setbuf(stdout, NULL);
286 freopen(logfile, "a", stderr);
287 setbuf(stderr, NULL);
288
289 logmsg("bu: invoked with %d args\n", argc);
290
291 if (argc < 2) {
292 logmsg("Not enough args (%d)\n", argc);
293 do_exit(1);
294 }
295
296 // progname args...
297 int optidx = 1;
298 const char* opname = argv[optidx++];
299
300 struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "/file_contexts" } };
301 sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
302
303 load_volume_table();
304
305 if (!strcmp(opname, "backup")) {
306 ui_print("Backup in progress...");
307 rc = do_backup(argc - optidx, &argv[optidx]);
308 } else if (!strcmp(opname, "restore")) {
309 ui_print("Restore in progress...");
310 rc = do_restore(argc - optidx, &argv[optidx]);
311 } else {
312 logmsg("Unknown operation %s\n", opname);
313 rc = 1;
314 }
315
316 close(adb_ofd);
317 close(adb_ifd);
318
319 sleep(1);
320
321 logmsg("bu exiting\n");
322
323 do_exit(rc);
324
325 return rc;
326}