Browse Source

recovery: bu: Implement backup/restore

Change-Id: I9e684868ce15aaaed3a40338dadc20b003b50ade
Tom Marshall 5 years ago
parent
commit
b76ac87825
5 changed files with 919 additions and 1 deletions
  1. 47
    1
      Android.mk
  2. 197
    0
      backup.cpp
  3. 382
    0
      bu.cpp
  4. 54
    0
      bu.h
  5. 239
    0
      restore.cpp

+ 47
- 1
Android.mk View File

@@ -269,7 +269,8 @@ endif
269 269
 
270 270
 LOCAL_REQUIRED_MODULES += \
271 271
     toybox_static \
272
-    recovery_mkshrc
272
+    recovery_mkshrc \
273
+    bu_recovery
273 274
 
274 275
 # Symlinks
275 276
 RECOVERY_TOOLS := \
@@ -299,6 +300,51 @@ LOCAL_SRC_FILES := etc/mkshrc
299 300
 LOCAL_MODULE_STEM := mkshrc
300 301
 include $(BUILD_PREBUILT)
301 302
 
303
+include $(CLEAR_VARS)
304
+LOCAL_MODULE := bu_recovery
305
+LOCAL_MODULE_STEM := bu
306
+LOCAL_MODULE_TAGS := optional
307
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
308
+LOCAL_FORCE_STATIC_EXECUTABLE := true
309
+LOCAL_SRC_FILES := \
310
+    bu.cpp \
311
+    backup.cpp \
312
+    restore.cpp \
313
+    roots.cpp
314
+LOCAL_CFLAGS += -DMINIVOLD
315
+LOCAL_CFLAGS += -Wno-unused-parameter
316
+LOCAL_STATIC_LIBRARIES += \
317
+    libext4_utils \
318
+    libsparse \
319
+    libmounts \
320
+    libz \
321
+    libminadbd \
322
+    libminui \
323
+    libfs_mgr \
324
+    libtar \
325
+    libcrypto \
326
+    libbase \
327
+    libcutils \
328
+    libutils \
329
+    liblog \
330
+    libselinux \
331
+    libm \
332
+    libc
333
+
334
+LOCAL_C_INCLUDES += \
335
+    system/core/fs_mgr/include \
336
+    system/core/include \
337
+    system/core/libcutils \
338
+    system/extras/ext4_utils \
339
+    system/vold \
340
+    external/libtar \
341
+    external/libtar/listhash \
342
+    external/openssl/include \
343
+    external/zlib \
344
+    bionic/libc/bionic
345
+
346
+include $(BUILD_EXECUTABLE)
347
+
302 348
 # Minizip static library
303 349
 include $(CLEAR_VARS)
304 350
 LOCAL_MODULE := libminizip_static

+ 197
- 0
backup.cpp View File

@@ -0,0 +1,197 @@
1
+#include <stdlib.h>
2
+#include <stdio.h>
3
+
4
+#include <sys/types.h>
5
+#include <sys/socket.h>
6
+#include <unistd.h>
7
+#include <sys/stat.h>
8
+#include <fcntl.h>
9
+#include <dirent.h>
10
+#include <sys/vfs.h>
11
+#include <time.h>
12
+
13
+#include "cutils/properties.h"
14
+
15
+#include <fs_mgr.h>
16
+#include "roots.h"
17
+
18
+#include "bu.h"
19
+
20
+using namespace android;
21
+
22
+static int append_sod(const char* opt_hash)
23
+{
24
+    const char* key;
25
+    char value[PROPERTY_VALUE_MAX];
26
+    char sodbuf[PROP_LINE_LEN*10];
27
+    char* p = sodbuf;
28
+
29
+    key = "hash.name";
30
+    strcpy(value, opt_hash);
31
+    p += sprintf(p, "%s=%s\n", key, value);
32
+
33
+    key = "ro.product.device";
34
+    property_get(key, value, "");
35
+    p += sprintf(p, "%s=%s\n", key, value);
36
+
37
+    for (int i = 0; i < MAX_PART; ++i) {
38
+        partspec* part = part_get(i);
39
+        if (!part)
40
+            break;
41
+        int fd = open(part->vol->blk_device, O_RDONLY);
42
+        part->size = part->used = lseek64(fd, 0, SEEK_END);
43
+        close(fd);
44
+        p += sprintf(p, "fs.%s.size=%llu\n", part->name, (unsigned long long)part->size);
45
+        p += sprintf(p, "fs.%s.used=%llu\n", part->name, (unsigned long long)part->used);
46
+    }
47
+
48
+    int rc = tar_append_file_contents(tar, "SOD", 0600,
49
+            getuid(), getgid(), sodbuf, p-sodbuf);
50
+    return rc;
51
+}
52
+
53
+static int append_eod(const char* opt_hash)
54
+{
55
+    char eodbuf[PROP_LINE_LEN*10];
56
+    char* p = eodbuf;
57
+    int n;
58
+
59
+    p += sprintf(p, "hash.datalen=%lu\n", (unsigned long)hash_datalen);
60
+
61
+    unsigned char digest[HASH_MAX_LENGTH];
62
+    char hexdigest[HASH_MAX_STRING_LENGTH];
63
+
64
+    if (!strcasecmp(opt_hash, "sha1")) {
65
+        SHA1_Final(digest, &sha_ctx);
66
+        for (n = 0; n < SHA_DIGEST_LENGTH; ++n) {
67
+            sprintf(hexdigest+2*n, "%02x", digest[n]);
68
+        }
69
+        p += sprintf(p, "hash.value=%s\n", hexdigest);
70
+    }
71
+    else { // default to md5
72
+        MD5_Final(digest, &md5_ctx);
73
+        for (n = 0; n < MD5_DIGEST_LENGTH; ++n) {
74
+            sprintf(hexdigest+2*n, "%02x", digest[n]);
75
+        }
76
+        p += sprintf(p, "hash.value=%s\n", hexdigest);
77
+    }
78
+
79
+    int rc = tar_append_file_contents(tar, "EOD", 0600,
80
+            getuid(), getgid(), eodbuf, p-eodbuf);
81
+    return rc;
82
+}
83
+
84
+static int tar_append_device_contents(TAR* t, const char* devname, const char* savename)
85
+{
86
+    struct stat st;
87
+    memset(&st, 0, sizeof(st));
88
+    if (lstat(devname, &st) != 0) {
89
+        logmsg("tar_append_device_contents: lstat %s failed\n", devname);
90
+        return -1;
91
+    }
92
+    st.st_mode = 0644 | S_IFREG;
93
+
94
+    int fd = open(devname, O_RDONLY);
95
+    if (fd < 0) {
96
+        logmsg("tar_append_device_contents: open %s failed\n", devname);
97
+        return -1;
98
+    }
99
+    st.st_size = lseek64(fd, 0, SEEK_END);
100
+    close(fd);
101
+
102
+    th_set_from_stat(t, &st);
103
+    th_set_path(t, savename);
104
+    if (th_write(t) != 0) {
105
+        logmsg("tar_append_device_contents: th_write failed\n");
106
+        return -1;
107
+    }
108
+    if (tar_append_regfile(t, devname) != 0) {
109
+        logmsg("tar_append_device_contents: tar_append_regfile %s failed\n", devname);
110
+        return -1;
111
+    }
112
+    return 0;
113
+}
114
+
115
+int do_backup(int argc, char **argv)
116
+{
117
+    int rc = 1;
118
+    int n;
119
+    int i;
120
+
121
+    const char* opt_compress = "gzip";
122
+    const char* opt_hash = "md5";
123
+
124
+    int optidx = 0;
125
+    while (optidx < argc && argv[optidx][0] == '-' && argv[optidx][1] == '-') {
126
+        char* optname = &argv[optidx][2];
127
+        ++optidx;
128
+        char* optval = strchr(optname, '=');
129
+        if (optval) {
130
+            *optval = '\0';
131
+            ++optval;
132
+        }
133
+        else {
134
+            if (optidx >= argc) {
135
+                logmsg("No argument to --%s\n", optname);
136
+                return -1;
137
+            }
138
+            optval = argv[optidx];
139
+            ++optidx;
140
+        }
141
+        if (!strcmp(optname, "compress")) {
142
+            opt_compress = optval;
143
+            logmsg("do_backup: compress=%s\n", opt_compress);
144
+        }
145
+        else if (!strcmp(optname, "hash")) {
146
+            opt_hash = optval;
147
+            logmsg("do_backup: hash=%s\n", opt_hash);
148
+        }
149
+        else {
150
+            logmsg("do_backup: invalid option name \"%s\"\n", optname);
151
+            return -1;
152
+        }
153
+    }
154
+    for (n = optidx; n < argc; ++n) {
155
+        const char* partname = argv[n];
156
+        if (*partname == '-')
157
+            ++partname;
158
+        if (part_add(partname) != 0) {
159
+            logmsg("Failed to add partition %s\n", partname);
160
+            return -1;
161
+        }
162
+    }
163
+
164
+    rc = create_tar(adb_ofd, opt_compress, "w");
165
+    if (rc != 0) {
166
+        logmsg("do_backup: cannot open tar stream\n");
167
+        return rc;
168
+    }
169
+
170
+    append_sod(opt_hash);
171
+
172
+    hash_name = strdup(opt_hash);
173
+
174
+    for (i = 0; i < MAX_PART; ++i) {
175
+        partspec* curpart = part_get(i);
176
+        if (!curpart)
177
+            break;
178
+
179
+        part_set(curpart);
180
+        rc = tar_append_device_contents(tar, curpart->vol->blk_device, curpart->name);
181
+    }
182
+
183
+    free(hash_name);
184
+    hash_name = NULL;
185
+
186
+    append_eod(opt_hash);
187
+
188
+    tar_append_eof(tar);
189
+
190
+    if (opt_compress)
191
+        gzflush(gzf, Z_FINISH);
192
+
193
+    logmsg("backup complete: rc=%d\n", rc);
194
+
195
+    return rc;
196
+}
197
+

+ 382
- 0
bu.cpp View File

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

+ 54
- 0
bu.h View File

@@ -0,0 +1,54 @@
1
+#include <utils/String8.h>
2
+
3
+#include <lib/libtar.h>
4
+#include <zlib.h>
5
+
6
+extern "C" {
7
+#include <openssl/sha.h>
8
+#include <openssl/md5.h>
9
+#ifndef MD5_DIGEST_STRING_LENGTH
10
+#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH*2+1)
11
+#endif
12
+#ifndef SHA_DIGEST_STRING_LENGTH
13
+#define SHA_DIGEST_STRING_LENGTH (SHA_DIGEST_LENGTH*2+1)
14
+#endif
15
+}
16
+
17
+#define HASH_MAX_LENGTH SHA_DIGEST_LENGTH
18
+#define HASH_MAX_STRING_LENGTH SHA_DIGEST_STRING_LENGTH
19
+
20
+#define PROP_LINE_LEN (PROPERTY_KEY_MAX+1+PROPERTY_VALUE_MAX+1+1)
21
+
22
+extern int adb_ifd;
23
+extern int adb_ofd;
24
+extern TAR* tar;
25
+extern gzFile gzf;
26
+
27
+extern char* hash_name;
28
+extern size_t hash_datalen;
29
+extern SHA_CTX sha_ctx;
30
+extern MD5_CTX md5_ctx;
31
+
32
+struct partspec {
33
+    char*       name;
34
+    char*       path;
35
+    Volume*     vol;
36
+    uint64_t    size;
37
+    uint64_t    used;
38
+    uint64_t    off;
39
+};
40
+#define MAX_PART 8
41
+
42
+extern void logmsg(const char* fmt, ...);
43
+
44
+extern int part_add(const char* name);
45
+extern partspec* part_get(int i);
46
+extern partspec* part_find(const char* name);
47
+extern void part_set(partspec* part);
48
+
49
+extern int update_progress(uint64_t off);
50
+
51
+extern int create_tar(int fd, const char* compress, const char* mode);
52
+
53
+extern int do_backup(int argc, char** argv);
54
+extern int do_restore(int argc, char** argv);

+ 239
- 0
restore.cpp View File

@@ -0,0 +1,239 @@
1
+#include <stdlib.h>
2
+#include <stdio.h>
3
+#include <stdarg.h>
4
+
5
+#include <sys/types.h>
6
+#include <sys/socket.h>
7
+#include <unistd.h>
8
+#include <sys/stat.h>
9
+#include <fcntl.h>
10
+#include <dirent.h>
11
+#include <sys/vfs.h>
12
+
13
+#include <cutils/properties.h>
14
+
15
+#include <lib/libtar.h>
16
+#include <zlib.h>
17
+
18
+#include <fs_mgr.h>
19
+#include "roots.h"
20
+
21
+#include "bu.h"
22
+
23
+using namespace android;
24
+
25
+static int verify_sod()
26
+{
27
+    const char* key;
28
+    char value[PROPERTY_VALUE_MAX];
29
+    char sodbuf[PROP_LINE_LEN*10];
30
+    size_t len;
31
+
32
+    len = sizeof(sodbuf);
33
+    if (tar_extract_file_contents(tar, sodbuf, &len) != 0) {
34
+        logmsg("tar_verify_sod: failed to extract file\n");
35
+        return -1;
36
+    }
37
+
38
+    char val_hashname[PROPERTY_VALUE_MAX];
39
+    memset(val_hashname, 0, sizeof(val_hashname));
40
+    char val_product[PROPERTY_VALUE_MAX];
41
+    memset(val_product, 0, sizeof(val_product));
42
+    char* p = sodbuf;
43
+    char* q;
44
+    while ((q = strchr(p, '\n')) != NULL) {
45
+        char* key = p;
46
+        *q = '\0';
47
+        logmsg("verify_sod: line=%s\n", p);
48
+        p = q+1;
49
+        char* val = strchr(key, '=');
50
+        if (val) {
51
+            *val = '\0';
52
+            ++val;
53
+            if (strcmp(key, "hash.name") == 0) {
54
+                strncpy(val_hashname, val, sizeof(val_hashname));
55
+            }
56
+            if (strcmp(key, "ro.product.device") == 0) {
57
+                strncpy(val_product, val, sizeof(val_product));
58
+            }
59
+            if (strncmp(key, "fs.", 3) == 0) {
60
+                char* name = key+3;
61
+                char* attr = strchr(name, '.');
62
+                if (attr) {
63
+                    *attr = '\0';
64
+                    ++attr;
65
+                    part_add(name);
66
+                    struct partspec* part = part_find(name);
67
+                    if (!strcmp(attr, "size")) {
68
+                        part->size = strtoul(val, NULL, 0);
69
+                    }
70
+                    if (!strcmp(attr, "used")) {
71
+                        part->used = strtoul(val, NULL, 0);
72
+                    }
73
+                }
74
+            }
75
+        }
76
+    }
77
+
78
+    if (!val_hashname[0]) {
79
+        logmsg("verify_sod: did not find hash.name\n");
80
+        return -1;
81
+    }
82
+    hash_name = strdup(val_hashname);
83
+
84
+    if (!val_product[0]) {
85
+        logmsg("verify_sod: did not find ro.product.device\n");
86
+        return -1;
87
+    }
88
+    key = "ro.product.device";
89
+    property_get(key, value, "");
90
+    if (strcmp(val_product, value) != 0) {
91
+        logmsg("verify_sod: product does not match\n");
92
+        return -1;
93
+    }
94
+
95
+    return 0;
96
+}
97
+
98
+static int verify_eod(size_t actual_hash_datalen,
99
+        SHA_CTX* actual_sha_ctx, MD5_CTX* actual_md5_ctx)
100
+{
101
+    int rc = -1;
102
+    char eodbuf[PROP_LINE_LEN*10];
103
+    size_t len;
104
+
105
+    len = sizeof(eodbuf);
106
+    if (tar_extract_file_contents(tar, eodbuf, &len) != 0) {
107
+        logmsg("verify_eod: failed to extract file\n");
108
+        return -1;
109
+    }
110
+
111
+    size_t reported_datalen = 0;
112
+    char reported_hash[HASH_MAX_STRING_LENGTH];
113
+    memset(reported_hash, 0, sizeof(reported_hash));
114
+    char* p = eodbuf;
115
+    char* q;
116
+    while ((q = strchr(p, '\n')) != NULL) {
117
+        char* key = p;
118
+        *q = '\0';
119
+        logmsg("verify_eod: line=%s\n", p);
120
+        p = q+1;
121
+        char* val = strchr(key, '=');
122
+        if (val) {
123
+            *val = '\0';
124
+            ++val;
125
+            if (strcmp(key, "hash.datalen") == 0) {
126
+                reported_datalen = strtoul(val, NULL, 0);
127
+            }
128
+            if (strcmp(key, "hash.value") == 0) {
129
+                memset(reported_hash, 0, sizeof(reported_hash));
130
+                strncpy(reported_hash, val, sizeof(reported_hash));
131
+            }
132
+        }
133
+    }
134
+
135
+    unsigned char digest[HASH_MAX_LENGTH];
136
+    char hexdigest[HASH_MAX_STRING_LENGTH];
137
+
138
+    int n;
139
+    if (hash_name != NULL && !strcasecmp(hash_name, "sha1")) {
140
+        SHA1_Final(digest, actual_sha_ctx);
141
+         for (n = 0; n < SHA_DIGEST_LENGTH; ++n) {
142
+             sprintf(hexdigest+2*n, "%02x", digest[n]);
143
+         }
144
+    }
145
+    else { // default to md5
146
+        MD5_Final(digest, actual_md5_ctx);
147
+        for (n = 0; n < MD5_DIGEST_LENGTH; ++n) {
148
+            sprintf(hexdigest+2*n, "%02x", digest[n]);
149
+        }
150
+    }
151
+
152
+    logmsg("verify_eod: expected=%d,%s\n", actual_hash_datalen, hexdigest);
153
+
154
+    logmsg("verify_eod: reported=%d,%s\n", reported_datalen, reported_hash);
155
+
156
+    if ((reported_datalen == actual_hash_datalen) &&
157
+            (memcmp(hexdigest, reported_hash, strlen(hexdigest)) == 0)) {
158
+        rc = 0;
159
+    }
160
+
161
+    return rc;
162
+}
163
+
164
+int do_restore(int argc, char **argv)
165
+{
166
+    int rc = 0;
167
+    ssize_t len;
168
+    const char* compress = "none";
169
+    char buf[512];
170
+
171
+    len = recv(adb_ifd, buf, sizeof(buf), MSG_PEEK);
172
+    if (len < 0) {
173
+        logmsg("do_restore: peek failed (%d:%s)\n", rc, strerror(errno));
174
+        return -1;
175
+    }
176
+    if (len < 2) {
177
+        logmsg("do_restore: peek returned %d\n", len);
178
+        return -1;
179
+    }
180
+    if (buf[0] == 0x1f && buf[1] == 0x8b) {
181
+        logmsg("do_restore: is gzip\n");
182
+        compress = "gzip";
183
+    }
184
+
185
+    create_tar(adb_ifd, compress, "r");
186
+
187
+    size_t save_hash_datalen;
188
+    SHA_CTX save_sha_ctx;
189
+    MD5_CTX save_md5_ctx;
190
+
191
+    while (1) {
192
+        save_hash_datalen = hash_datalen;
193
+        memcpy(&save_sha_ctx, &sha_ctx, sizeof(SHA_CTX));
194
+        memcpy(&save_md5_ctx, &md5_ctx, sizeof(MD5_CTX));
195
+        rc = th_read(tar);
196
+        if (rc != 0) {
197
+            if (rc == 1) { // EOF
198
+                rc = 0;
199
+            }
200
+            break;
201
+        }
202
+        char* pathname = th_get_pathname(tar);
203
+        logmsg("do_restore: extract %s\n", pathname);
204
+        if (!strcmp(pathname, "SOD")) {
205
+            rc = verify_sod();
206
+            logmsg("do_restore: tar_verify_sod returned %d\n", rc);
207
+        }
208
+        else if (!strcmp(pathname, "EOD")) {
209
+            rc = verify_eod(save_hash_datalen, &save_sha_ctx, &save_md5_ctx);
210
+            logmsg("do_restore: tar_verify_eod returned %d\n", rc);
211
+        }
212
+        else {
213
+            char mnt[PATH_MAX];
214
+            snprintf(mnt, sizeof(mnt), "/%s", pathname);
215
+            Volume* vol = volume_for_mount_point(mnt);
216
+            if (vol != NULL && vol->fs_type != NULL) {
217
+                partspec* curpart = part_find(pathname);
218
+                part_set(curpart);
219
+                rc = tar_extract_file(tar, vol->blk_device);
220
+            }
221
+            else {
222
+                logmsg("do_restore: cannot find volume for %s\n", mnt);
223
+            }
224
+        }
225
+        free(pathname);
226
+        if (rc != 0) {
227
+            logmsg("do_restore: extract failed, rc=%d\n", rc);
228
+            break;
229
+        }
230
+    }
231
+
232
+    tar_close(tar);
233
+    logmsg("do_restore: rc=%d\n", rc);
234
+
235
+    free(hash_name);
236
+    hash_name = NULL;
237
+
238
+    return rc;
239
+}