blob: 8a2e9ce9ce3938f9ea3ec388bac47a0984e082f9 [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
2 * Copyright (C) 2011 The Android Open Source 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 <assert.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <limits.h>
21#include <paths.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <unistd.h>
29
30#include <ctype.h>
31#include "cutils/misc.h"
32#include "cutils/properties.h"
33#include <dirent.h>
34#include <getopt.h>
35#include <linux/input.h>
36#include <signal.h>
37#include <sys/limits.h>
38#include <termios.h>
39#include <time.h>
40#include <sys/vfs.h>
41
42#include "tw_reboot.h"
43#include "bootloader.h"
44#include "common.h"
45#include "extra-functions.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040046#include "minuitwrp/minui.h"
47#include "minzip/DirUtil.h"
48#include "minzip/Zip.h"
49#include "recovery_ui.h"
50#include "roots.h"
51#include "data.h"
52#include "variables.h"
Dees_Troy657c3092012-09-10 20:32:10 -040053#include "mincrypt/rsa.h"
54#include "verifier.h"
55#include "mincrypt/sha.h"
56
57#ifndef PUBLIC_KEYS_FILE
58#define PUBLIC_KEYS_FILE "/res/keys"
59#endif
60#ifndef ASSUMED_UPDATE_BINARY_NAME
61#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
62#endif
63enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
Dees_Troy51a0e822012-09-05 15:24:24 -040064
65//kang system() from bionic/libc/unistd and rename it __system() so we can be even more hackish :)
66#undef _PATH_BSHELL
67#define _PATH_BSHELL "/sbin/sh"
68
Dees_Troy51a0e822012-09-05 15:24:24 -040069extern char **environ;
70
71int __system(const char *command) {
72 pid_t pid;
73 sig_t intsave, quitsave;
74 sigset_t mask, omask;
75 int pstat;
76 char *argp[] = {"sh", "-c", NULL, NULL};
77
78 if (!command) /* just checking... */
79 return(1);
80
81 argp[2] = (char *)command;
82
83 sigemptyset(&mask);
84 sigaddset(&mask, SIGCHLD);
85 sigprocmask(SIG_BLOCK, &mask, &omask);
86 switch (pid = vfork()) {
87 case -1: /* error */
88 sigprocmask(SIG_SETMASK, &omask, NULL);
89 return(-1);
90 case 0: /* child */
91 sigprocmask(SIG_SETMASK, &omask, NULL);
92 execve(_PATH_BSHELL, argp, environ);
93 _exit(127);
94 }
95
96 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
97 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
98 pid = waitpid(pid, (int *)&pstat, 0);
99 sigprocmask(SIG_SETMASK, &omask, NULL);
100 (void)bsd_signal(SIGINT, intsave);
101 (void)bsd_signal(SIGQUIT, quitsave);
102 return (pid == -1 ? -1 : pstat);
103}
104
105static struct pid {
106 struct pid *next;
107 FILE *fp;
108 pid_t pid;
109} *pidlist;
110
111FILE *__popen(const char *program, const char *type) {
112 struct pid * volatile cur;
113 FILE *iop;
114 int pdes[2];
115 pid_t pid;
116
117 if ((*type != 'r' && *type != 'w') || type[1] != '\0') {
118 errno = EINVAL;
119 return (NULL);
120 }
121
122 if ((cur = malloc(sizeof(struct pid))) == NULL)
123 return (NULL);
124
125 if (pipe(pdes) < 0) {
126 free(cur);
127 return (NULL);
128 }
129
130 switch (pid = vfork()) {
131 case -1: /* Error. */
132 (void)close(pdes[0]);
133 (void)close(pdes[1]);
134 free(cur);
135 return (NULL);
136 /* NOTREACHED */
137 case 0: /* Child. */
138 {
139 struct pid *pcur;
140 /*
141 * because vfork() instead of fork(), must leak FILE *,
142 * but luckily we are terminally headed for an execl()
143 */
144 for (pcur = pidlist; pcur; pcur = pcur->next)
145 close(fileno(pcur->fp));
146
147 if (*type == 'r') {
148 int tpdes1 = pdes[1];
149
150 (void) close(pdes[0]);
151 /*
152 * We must NOT modify pdes, due to the
153 * semantics of vfork.
154 */
155 if (tpdes1 != STDOUT_FILENO) {
156 (void)dup2(tpdes1, STDOUT_FILENO);
157 (void)close(tpdes1);
158 tpdes1 = STDOUT_FILENO;
159 }
160 } else {
161 (void)close(pdes[1]);
162 if (pdes[0] != STDIN_FILENO) {
163 (void)dup2(pdes[0], STDIN_FILENO);
164 (void)close(pdes[0]);
165 }
166 }
167 execl(_PATH_BSHELL, "sh", "-c", program, (char *)NULL);
168 _exit(127);
169 /* NOTREACHED */
170 }
171 }
172
173 /* Parent; assume fdopen can't fail. */
174 if (*type == 'r') {
175 iop = fdopen(pdes[0], type);
176 (void)close(pdes[1]);
177 } else {
178 iop = fdopen(pdes[1], type);
179 (void)close(pdes[0]);
180 }
181
182 /* Link into list of file descriptors. */
183 cur->fp = iop;
184 cur->pid = pid;
185 cur->next = pidlist;
186 pidlist = cur;
187
188 return (iop);
189}
190
191/*
192 * pclose --
193 * Pclose returns -1 if stream is not associated with a `popened' command,
194 * if already `pclosed', or waitpid returns an error.
195 */
196int __pclose(FILE *iop) {
197 struct pid *cur, *last;
198 int pstat;
199 pid_t pid;
200
201 /* Find the appropriate file pointer. */
202 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
203 if (cur->fp == iop)
204 break;
205
206 if (cur == NULL)
207 return (-1);
208
209 (void)fclose(iop);
210
211 do {
212 pid = waitpid(cur->pid, &pstat, 0);
213 } while (pid == -1 && errno == EINTR);
214
215 /* Remove the entry from the linked list. */
216 if (last == NULL)
217 pidlist = cur->next;
218 else
219 last->next = cur->next;
220 free(cur);
221
222 return (pid == -1 ? -1 : pstat);
223}
224
Dees_Troy51a0e822012-09-05 15:24:24 -0400225char* get_path (char* path) {
226 char *s;
227
228 /* Go to the end of the string. */
229 s = path + strlen(path) - 1;
230
231 /* Strip off trailing /s (unless it is also the leading /). */
232 while (path < s && s[0] == '/')
233 s--;
234
235 /* Strip the last component. */
236 while (path <= s && s[0] != '/')
237 s--;
238
239 while (path < s && s[0] == '/')
240 s--;
241
242 if (s < path)
243 return ".";
244
245 s[1] = '\0';
246 return path;
247}
248
249char* basename(char* name) {
250 const char* base;
251 for (base = name; *name; name++)
252 {
253 if(*name == '/')
254 {
255 base = name + 1;
256 }
257 }
258 return (char *) base;
259}
260
261/*
262 Checks md5 for a path
263 Return values:
264 -1 : MD5 does not exist
265 0 : Failed
266 1 : Success
267*/
268int check_md5(char* path) {
269 int o;
270 char cmd[PATH_MAX + 30];
271 char md5file[PATH_MAX + 40];
272 strcpy(md5file, path);
273 strcat(md5file, ".md5");
274 char dirpath[PATH_MAX];
275 char* file;
276 if (access(md5file, F_OK ) != -1) {
277 strcpy(dirpath, md5file);
278 get_path(dirpath);
279 chdir(dirpath);
280 file = basename(md5file);
281 sprintf(cmd, "/sbin/busybox md5sum -c '%s'", file);
282 FILE * cs = __popen(cmd, "r");
283 char cs_s[PATH_MAX + 50];
284 fgets(cs_s, PATH_MAX + 50, cs);
285 char* OK = strstr(cs_s, "OK");
286 if (OK != NULL) {
287 printf("MD5 is good. returning 1\n");
288 o = 1;
289 }
290 else {
291 printf("MD5 is bad. return -2\n");
292 o = -2;
293 }
294
295 __pclose(cs);
296 }
297 else {
298 //No md5 file
299 printf("setting o to -1\n");
300 o = -1;
301 }
302
303 return o;
304}
305
Dees_Troy657c3092012-09-10 20:32:10 -0400306static void set_sdcard_update_bootloader_message() {
307 struct bootloader_message boot;
308 memset(&boot, 0, sizeof(boot));
309 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
310 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
311 set_bootloader_message(&boot);
312}
Dees_Troy7d15c252012-09-05 20:47:21 -0400313
Dees_Troy657c3092012-09-10 20:32:10 -0400314int TWtry_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
315 const ZipEntry* binary_entry =
316 mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
317 if (binary_entry == NULL) {
318 mzCloseZipArchive(zip);
Dees_Troy7d15c252012-09-05 20:47:21 -0400319 return INSTALL_CORRUPT;
320 }
Dees_Troy657c3092012-09-10 20:32:10 -0400321 const char* binary = "/tmp/update_binary";
322 unlink(binary);
323 int fd = creat(binary, 0755);
324 if (fd < 0) {
325 mzCloseZipArchive(zip);
326 LOGE("Can't make %s\n", binary);
327 return INSTALL_ERROR;
Dees_Troy7d15c252012-09-05 20:47:21 -0400328 }
Dees_Troy657c3092012-09-10 20:32:10 -0400329 bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
330 close(fd);
331 mzCloseZipArchive(zip);
Dees_Troy7d15c252012-09-05 20:47:21 -0400332
Dees_Troy657c3092012-09-10 20:32:10 -0400333 if (!ok) {
334 LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
335 return INSTALL_ERROR;
336 }
Dees_Troy7d15c252012-09-05 20:47:21 -0400337
Dees_Troy657c3092012-09-10 20:32:10 -0400338 int pipefd[2];
339 pipe(pipefd);
Dees_Troy7d15c252012-09-05 20:47:21 -0400340
Dees_Troy657c3092012-09-10 20:32:10 -0400341 // When executing the update binary contained in the package, the
342 // arguments passed are:
343 //
344 // - the version number for this interface
345 //
346 // - an fd to which the program can write in order to update the
347 // progress bar. The program can write single-line commands:
348 //
349 // progress <frac> <secs>
350 // fill up the next <frac> part of of the progress bar
351 // over <secs> seconds. If <secs> is zero, use
352 // set_progress commands to manually control the
353 // progress of this segment of the bar
354 //
355 // set_progress <frac>
356 // <frac> should be between 0.0 and 1.0; sets the
357 // progress bar within the segment defined by the most
358 // recent progress command.
359 //
360 // firmware <"hboot"|"radio"> <filename>
361 // arrange to install the contents of <filename> in the
362 // given partition on reboot.
363 //
364 // (API v2: <filename> may start with "PACKAGE:" to
365 // indicate taking a file from the OTA package.)
366 //
367 // (API v3: this command no longer exists.)
368 //
369 // ui_print <string>
370 // display <string> on the screen.
371 //
372 // - the name of the package zip file.
373 //
374
375 const char** args = (const char**)malloc(sizeof(char*) * 5);
376 args[0] = binary;
377 args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
378 char* temp = (char*)malloc(10);
379 sprintf(temp, "%d", pipefd[1]);
380 args[2] = temp;
381 args[3] = (char*)path;
382 args[4] = NULL;
383
384 pid_t pid = fork();
385 if (pid == 0) {
386 close(pipefd[0]);
387 execv(binary, (char* const*)args);
388 fprintf(stdout, "E:Can't run %s (error)\n", binary);
389 _exit(-1);
390 }
391 close(pipefd[1]);
392 *wipe_cache = 0;
393
394 char buffer[1024];
395 FILE* from_child = fdopen(pipefd[0], "r");
396 LOGI("8\n");
397 while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
398 char* command = strtok(buffer, " \n");
399 if (command == NULL) {
400 continue;
401 } else if (strcmp(command, "progress") == 0) {
402 char* fraction_s = strtok(NULL, " \n");
403 char* seconds_s = strtok(NULL, " \n");
404
405 float fraction = strtof(fraction_s, NULL);
406 int seconds = strtol(seconds_s, NULL, 10);
407
408 //ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);
409 } else if (strcmp(command, "set_progress") == 0) {
410 char* fraction_s = strtok(NULL, " \n");
411 float fraction = strtof(fraction_s, NULL);
412 //ui->SetProgress(fraction);
413 } else if (strcmp(command, "ui_print") == 0) {
414 char* str = strtok(NULL, "\n");
415 if (str) {
416 //ui->Print("%s", str);
417 } else {
418 //ui->Print("\n");
419 }
420 } else if (strcmp(command, "wipe_cache") == 0) {
421 *wipe_cache = 1;
422 } else if (strcmp(command, "clear_display") == 0) {
423 //ui->SetBackground(RecoveryUI::NONE);
424 } else {
425 LOGE("unknown command [%s]\n", command);
426 }
427 }
428 fclose(from_child);
429
430 int status;
431 waitpid(pid, &status, 0);
432 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
433 LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
434 return INSTALL_ERROR;
435 }
436 return INSTALL_SUCCESS;
437}
438
439// Look for an RSA signature embedded in the .ZIP file comment given
440// the path to the zip. Verify it matches one of the given public
441// keys.
442//
443// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered
444// or no key matches the signature).
445
446int TWverify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys) {
447 //ui->SetProgress(0.0);
448
449 FILE* f = fopen(path, "rb");
450 if (f == NULL) {
451 LOGE("failed to open %s (%s)\n", path, strerror(errno));
452 return VERIFY_FAILURE;
453 }
454
455 // An archive with a whole-file signature will end in six bytes:
456 //
457 // (2-byte signature start) $ff $ff (2-byte comment size)
458 //
459 // (As far as the ZIP format is concerned, these are part of the
460 // archive comment.) We start by reading this footer, this tells
461 // us how far back from the end we have to start reading to find
462 // the whole comment.
463
464#define FOOTER_SIZE 6
465
466 if (fseek(f, -FOOTER_SIZE, SEEK_END) != 0) {
467 LOGE("failed to seek in %s (%s)\n", path, strerror(errno));
468 fclose(f);
469 return VERIFY_FAILURE;
470 }
471
472 unsigned char footer[FOOTER_SIZE];
473 if (fread(footer, 1, FOOTER_SIZE, f) != FOOTER_SIZE) {
474 LOGE("failed to read footer from %s (%s)\n", path, strerror(errno));
475 fclose(f);
476 return VERIFY_FAILURE;
477 }
478
479 if (footer[2] != 0xff || footer[3] != 0xff) {
480 fclose(f);
481 return VERIFY_FAILURE;
482 }
483
484 size_t comment_size = footer[4] + (footer[5] << 8);
485 size_t signature_start = footer[0] + (footer[1] << 8);
486 LOGI("comment is %d bytes; signature %d bytes from end\n",
487 comment_size, signature_start);
488
489 if (signature_start - FOOTER_SIZE < RSANUMBYTES) {
490 // "signature" block isn't big enough to contain an RSA block.
491 LOGE("signature is too short\n");
492 fclose(f);
493 return VERIFY_FAILURE;
494 }
495
496#define EOCD_HEADER_SIZE 22
497
498 // The end-of-central-directory record is 22 bytes plus any
499 // comment length.
500 size_t eocd_size = comment_size + EOCD_HEADER_SIZE;
501
502 if (fseek(f, -eocd_size, SEEK_END) != 0) {
503 LOGE("failed to seek in %s (%s)\n", path, strerror(errno));
504 fclose(f);
505 return VERIFY_FAILURE;
506 }
507
508 // Determine how much of the file is covered by the signature.
509 // This is everything except the signature data and length, which
510 // includes all of the EOCD except for the comment length field (2
511 // bytes) and the comment data.
512 size_t signed_len = ftell(f) + EOCD_HEADER_SIZE - 2;
513
514 unsigned char* eocd = (unsigned char*)malloc(eocd_size);
515 if (eocd == NULL) {
516 LOGE("malloc for EOCD record failed\n");
517 fclose(f);
518 return VERIFY_FAILURE;
519 }
520 if (fread(eocd, 1, eocd_size, f) != eocd_size) {
521 LOGE("failed to read eocd from %s (%s)\n", path, strerror(errno));
522 fclose(f);
523 return VERIFY_FAILURE;
524 }
525
526 // If this is really is the EOCD record, it will begin with the
527 // magic number $50 $4b $05 $06.
528 if (eocd[0] != 0x50 || eocd[1] != 0x4b ||
529 eocd[2] != 0x05 || eocd[3] != 0x06) {
530 LOGE("signature length doesn't match EOCD marker\n");
531 fclose(f);
532 return VERIFY_FAILURE;
533 }
534
535 size_t i;
536 for (i = 4; i < eocd_size-3; ++i) {
537 if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b &&
538 eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
539 // if the sequence $50 $4b $05 $06 appears anywhere after
540 // the real one, minzip will find the later (wrong) one,
541 // which could be exploitable. Fail verification if
542 // this sequence occurs anywhere after the real one.
543 LOGE("EOCD marker occurs after start of EOCD\n");
544 fclose(f);
545 return VERIFY_FAILURE;
546 }
547 }
548
549#define BUFFER_SIZE 4096
550
551 SHA_CTX ctx;
552 SHA_init(&ctx);
553 unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);
554 if (buffer == NULL) {
555 LOGE("failed to alloc memory for sha1 buffer\n");
556 fclose(f);
557 return VERIFY_FAILURE;
558 }
559
560 double frac = -1.0;
561 size_t so_far = 0;
562 fseek(f, 0, SEEK_SET);
563 while (so_far < signed_len) {
564 size_t size = BUFFER_SIZE;
565 if (signed_len - so_far < size) size = signed_len - so_far;
566 if (fread(buffer, 1, size, f) != size) {
567 LOGE("failed to read data from %s (%s)\n", path, strerror(errno));
568 fclose(f);
569 return VERIFY_FAILURE;
570 }
571 SHA_update(&ctx, buffer, size);
572 so_far += size;
573 double f = so_far / (double)signed_len;
574 if (f > frac + 0.02 || size == so_far) {
575 //ui->SetProgress(f);
576 frac = f;
577 }
578 }
579 fclose(f);
580 free(buffer);
581
582 const uint8_t* sha1 = SHA_final(&ctx);
583 for (i = 0; i < numKeys; ++i) {
584 // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
585 // the signing tool appends after the signature itself.
586 if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES,
587 RSANUMBYTES, sha1)) {
588 LOGI("whole-file signature verified against key %d\n", i);
589 free(eocd);
590 return VERIFY_SUCCESS;
591 }
592 }
593 free(eocd);
594 LOGE("failed to verify whole-file signature\n");
595 return VERIFY_FAILURE;
596}
597
598// Reads a file containing one or more public keys as produced by
599// DumpPublicKey: this is an RSAPublicKey struct as it would appear
600// as a C source literal, eg:
601//
602// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
603//
604// (Note that the braces and commas in this example are actual
605// characters the parser expects to find in the file; the ellipses
606// indicate more numbers omitted from this example.)
607//
608// The file may contain multiple keys in this format, separated by
609// commas. The last key must not be followed by a comma.
610//
611// Returns NULL if the file failed to parse, or if it contain zero keys.
612static RSAPublicKey*
613TWload_keys(const char* filename, int* numKeys) {
614 RSAPublicKey* out = NULL;
615 *numKeys = 0;
616
617 FILE* f = fopen(filename, "r");
618 if (f == NULL) {
619 LOGE("opening %s: ERROR\n", filename);
620 goto exit;
621 }
622
623 {
624 int i;
625 bool done = false;
626 while (!done) {
627 ++*numKeys;
628 out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
629 RSAPublicKey* key = out + (*numKeys - 1);
630 if (fscanf(f, " { %i , 0x%x , { %u",
631 &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
632 goto exit;
633 }
634 if (key->len != RSANUMWORDS) {
635 LOGE("key length (%d) does not match expected size\n", key->len);
636 goto exit;
637 }
638 for (i = 1; i < key->len; ++i) {
639 if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
640 }
641 if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
642 for (i = 1; i < key->len; ++i) {
643 if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
644 }
645 fscanf(f, " } } ");
646
647 // if the line ends in a comma, this file has more keys.
648 switch (fgetc(f)) {
649 case ',':
650 // more keys to come.
651 break;
652
653 case EOF:
654 done = true;
655 break;
656
657 default:
658 LOGE("unexpected character between keys\n");
659 goto exit;
660 }
661 }
662 }
663
664 fclose(f);
665 return out;
666
667exit:
668 if (f) fclose(f);
669 free(out);
670 *numKeys = 0;
671 return NULL;
672}
673
674int TWinstall_zip(const char* path, int* wipe_cache) {
675 int err;
676
677 if (DataManager_GetIntValue(TW_SIGNED_ZIP_VERIFY_VAR)) {
678 int numKeys;
679 RSAPublicKey* loadedKeys = TWload_keys(PUBLIC_KEYS_FILE, &numKeys);
680 if (loadedKeys == NULL) {
681 LOGE("Failed to load keys\n");
682 return -1;
683 }
684 LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
685
686 // Give verification half the progress bar...
687 //ui->Print("Verifying update package...\n");
688 //ui->SetProgressType(RecoveryUI::DETERMINATE);
689 //ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
690
691 err = TWverify_file(path, loadedKeys, numKeys);
692 free(loadedKeys);
693 LOGI("verify_file returned %d\n", err);
694 if (err != VERIFY_SUCCESS) {
695 LOGE("signature verification failed\n");
696 return -1;
697 }
698 }
699 /* Try to open the package.
Dees_Troy7d15c252012-09-05 20:47:21 -0400700 */
701 ZipArchive zip;
702 err = mzOpenZipArchive(path, &zip);
703 if (err != 0) {
704 LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
705 return INSTALL_CORRUPT;
706 }
707
708 /* Verify and install the contents of the package.
709 */
Dees_Troy657c3092012-09-10 20:32:10 -0400710 //ui->Print("Installing update...\n");
711 return TWtry_update_binary(path, &zip, wipe_cache);
Dees_Troy51a0e822012-09-05 15:24:24 -0400712}
713
714//partial kangbang from system/vold
715#ifndef CUSTOM_LUN_FILE
716#define CUSTOM_LUN_FILE "/sys/devices/platform/usb_mass_storage/lun%d/file"
717#endif
718
719int usb_storage_enable(void)
720{
721 int fd;
722 char lun_file[255];
723
724 if (DataManager_GetIntValue(TW_HAS_DUAL_STORAGE) == 1 && DataManager_GetIntValue(TW_HAS_DATA_MEDIA) == 0) {
725 Volume *vol = volume_for_path(DataManager_GetSettingsStoragePath());
726 if (!vol)
727 {
728 LOGE("Unable to locate volume information.");
729 return -1;
730 }
731
732 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
733
734 if ((fd = open(lun_file, O_WRONLY)) < 0)
735 {
736 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
737 return -1;
738 }
739
740 if ((write(fd, vol->device, strlen(vol->device)) < 0) &&
741 (!vol->device2 || (write(fd, vol->device, strlen(vol->device2)) < 0))) {
742 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
743 close(fd);
744 return -1;
745 }
746 close(fd);
747
748 Volume *vol2 = volume_for_path(DataManager_GetStrValue(TW_EXTERNAL_PATH));
749 if (!vol)
750 {
751 LOGE("Unable to locate volume information.\n");
752 return -1;
753 }
754
755 sprintf(lun_file, CUSTOM_LUN_FILE, 1);
756
757 if ((fd = open(lun_file, O_WRONLY)) < 0)
758 {
759 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
760 return -1;
761 }
762
763 if ((write(fd, vol2->device, strlen(vol2->device)) < 0) &&
764 (!vol2->device2 || (write(fd, vol2->device, strlen(vol2->device2)) < 0))) {
765 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
766 close(fd);
767 return -1;
768 }
769 close(fd);
770 } else {
771 if (DataManager_GetIntValue(TW_HAS_DATA_MEDIA) == 0)
772 strcpy(lun_file, DataManager_GetCurrentStoragePath());
773 else
774 strcpy(lun_file, DataManager_GetStrValue(TW_EXTERNAL_PATH));
775
776 Volume *vol = volume_for_path(lun_file);
777 if (!vol)
778 {
779 LOGE("Unable to locate volume information.\n");
780 return -1;
781 }
782
783 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
784
785 if ((fd = open(lun_file, O_WRONLY)) < 0)
786 {
787 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
788 return -1;
789 }
790
791 if ((write(fd, vol->device, strlen(vol->device)) < 0) &&
792 (!vol->device2 || (write(fd, vol->device, strlen(vol->device2)) < 0))) {
793 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
794 close(fd);
795 return -1;
796 }
797 close(fd);
798 }
799 return 0;
800}
801
802int usb_storage_disable(void)
803{
804 int fd, index;
805 char lun_file[255];
806
807 for (index=0; index<2; index++) {
808 sprintf(lun_file, CUSTOM_LUN_FILE, index);
809
810 if ((fd = open(lun_file, O_WRONLY)) < 0)
811 {
812 if (index == 0)
813 LOGE("Unable to open ums lunfile '%s': (%s)", lun_file, strerror(errno));
814 return -1;
815 }
816
817 char ch = 0;
818 if (write(fd, &ch, 1) < 0)
819 {
820 if (index == 0)
821 LOGE("Unable to write to ums lunfile '%s': (%s)", lun_file, strerror(errno));
822 close(fd);
823 return -1;
824 }
825
826 close(fd);
827 }
828 return 0;
829}
830
831void wipe_dalvik_cache()
832{
833 //ui_set_background(BACKGROUND_ICON_WIPE);
834 ensure_path_mounted("/data");
835 ensure_path_mounted("/cache");
836 ui_print("\n-- Wiping Dalvik Cache Directories...\n");
837 __system("rm -rf /data/dalvik-cache");
838 ui_print("Cleaned: /data/dalvik-cache...\n");
839 __system("rm -rf /cache/dalvik-cache");
840 ui_print("Cleaned: /cache/dalvik-cache...\n");
841 __system("rm -rf /cache/dc");
842 ui_print("Cleaned: /cache/dc\n");
843
844 struct stat st;
845 LOGE("TODO: Re-implement wipe dalvik into Partition Manager!\n");
846 if (1) //if (0 != stat(sde.blk, &st))
847 {
848 ui_print("/sd-ext not present, skipping\n");
849 } else {
850 __system("mount /sd-ext");
851 LOGI("Mounting /sd-ext\n");
852 if (stat("/sd-ext/dalvik-cache",&st) == 0)
853 {
854 __system("rm -rf /sd-ext/dalvik-cache");
855 ui_print("Cleaned: /sd-ext/dalvik-cache...\n");
856 }
857 }
858 ensure_path_unmounted("/data");
859 ui_print("-- Dalvik Cache Directories Wipe Complete!\n\n");
860 //ui_set_background(BACKGROUND_ICON_MAIN);
861 //if (!ui_text_visible()) return;
862}
863
864// BATTERY STATS
865void wipe_battery_stats()
866{
867 ensure_path_mounted("/data");
868 struct stat st;
869 if (0 != stat("/data/system/batterystats.bin", &st))
870 {
871 ui_print("No Battery Stats Found. No Need To Wipe.\n");
872 } else {
873 //ui_set_background(BACKGROUND_ICON_WIPE);
874 remove("/data/system/batterystats.bin");
875 ui_print("Cleared: Battery Stats...\n");
876 ensure_path_unmounted("/data");
877 }
878}
879
880// ROTATION SETTINGS
881void wipe_rotate_data()
882{
883 //ui_set_background(BACKGROUND_ICON_WIPE);
884 ensure_path_mounted("/data");
885 __system("rm -r /data/misc/akmd*");
886 __system("rm -r /data/misc/rild*");
887 ui_print("Cleared: Rotatation Data...\n");
888 ensure_path_unmounted("/data");
889}
890
891void fix_perms()
892{
893 ensure_path_mounted("/data");
894 ensure_path_mounted("/system");
895 //ui_show_progress(1,30);
896 ui_print("\n-- Fixing Permissions\n");
897 ui_print("This may take a few minutes.\n");
898 __system("./sbin/fix_permissions.sh");
899 ui_print("-- Done.\n\n");
900 //ui_reset_progress();
901}
902
903int get_battery_level(void)
904{
905 static int lastVal = -1;
906 static time_t nextSecCheck = 0;
907
908 struct timeval curTime;
909 gettimeofday(&curTime, NULL);
910 if (curTime.tv_sec > nextSecCheck)
911 {
912 char cap_s[4];
913 FILE * cap = fopen("/sys/class/power_supply/battery/capacity","rt");
914 if (cap)
915 {
916 fgets(cap_s, 4, cap);
917 fclose(cap);
918 lastVal = atoi(cap_s);
919 if (lastVal > 100) lastVal = 101;
920 if (lastVal < 0) lastVal = 0;
921 }
922 nextSecCheck = curTime.tv_sec + 60;
923 }
924 return lastVal;
925}
926
927char*
928print_batt_cap() {
929 char* full_cap_s = (char*)malloc(30);
930 char full_cap_a[30];
931
932 int cap_i = get_battery_level();
933
934 //int len = strlen(cap_s);
935 //if (cap_s[len-1] == '\n') {
936 // cap_s[len-1] = 0;
937 //}
938
939 // Get a usable time
940 struct tm *current;
941 time_t now;
942 now = time(0);
943 current = localtime(&now);
944
945 sprintf(full_cap_a, "Battery Level: %i%% @ %02D:%02D", cap_i, current->tm_hour, current->tm_min);
946 strcpy(full_cap_s, full_cap_a);
947
948 return full_cap_s;
949}
950
951void update_tz_environment_variables() {
952 setenv("TZ", DataManager_GetStrValue(TW_TIME_ZONE_VAR), 1);
953 tzset();
954}
955
956void run_script(const char *str1, const char *str2, const char *str3, const char *str4, const char *str5, const char *str6, const char *str7, int request_confirm)
957{
958 ui_print("%s", str1);
959 //ui_clear_key_queue();
960 ui_print("\nPress Power to confirm,");
961 ui_print("\nany other key to abort.\n");
962 int confirm;
963 /*if (request_confirm) // this option is used to skip the confirmation when the gui is in use
964 confirm = ui_wait_key();
965 else*/
966 confirm = KEY_POWER;
967
968 if (confirm == BTN_MOUSE || confirm == KEY_POWER || confirm == SELECT_ITEM) {
969 ui_print("%s", str2);
970 pid_t pid = fork();
971 if (pid == 0) {
972 char *args[] = { "/sbin/sh", "-c", (char*)str3, "1>&2", NULL };
973 execv("/sbin/sh", args);
974 fprintf(stderr, str4, strerror(errno));
975 _exit(-1);
976 }
977 int status;
978 while (waitpid(pid, &status, WNOHANG) == 0) {
979 ui_print(".");
980 sleep(1);
981 }
982 ui_print("\n");
983 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
984 ui_print("%s", str5);
985 } else {
986 ui_print("%s", str6);
987 }
988 } else {
989 ui_print("%s", str7);
990 }
991 //if (!ui_text_visible()) return;
992}
993
994void install_htc_dumlock(void)
995{
996 struct statfs fs1, fs2;
997 int need_libs = 0;
998
999 ui_print("Installing HTC Dumlock to system...\n");
1000 ensure_path_mounted("/system");
1001 __system("cp /res/htcd/htcdumlocksys /system/bin/htcdumlock && chmod 755 /system/bin/htcdumlock");
1002 if (statfs("/system/bin/flash_image", &fs1) != 0) {
1003 ui_print("Installing flash_image...\n");
1004 __system("cp /res/htcd/flash_imagesys /system/bin/flash_image && chmod 755 /system/bin/flash_image");
1005 need_libs = 1;
1006 } else
1007 ui_print("flash_image is already installed, skipping...\n");
1008 if (statfs("/system/bin/dump_image", &fs2) != 0) {
1009 ui_print("Installing dump_image...\n");
1010 __system("cp /res/htcd/dump_imagesys /system/bin/dump_image && chmod 755 /system/bin/dump_image");
1011 need_libs = 1;
1012 } else
1013 ui_print("dump_image is already installed, skipping...\n");
1014 if (need_libs) {
1015 ui_print("Installing libs needed for flash_image and dump_image...\n");
1016 __system("cp /res/htcd/libbmlutils.so /system/lib && chmod 755 /system/lib/libbmlutils.so");
1017 __system("cp /res/htcd/libflashutils.so /system/lib && chmod 755 /system/lib/libflashutils.so");
1018 __system("cp /res/htcd/libmmcutils.so /system/lib && chmod 755 /system/lib/libmmcutils.so");
1019 __system("cp /res/htcd/libmtdutils.so /system/lib && chmod 755 /system/lib/libmtdutils.so");
1020 }
1021 ui_print("Installing HTC Dumlock app...\n");
1022 ensure_path_mounted("/data");
1023 mkdir("/data/app", 0777);
1024 __system("rm /data/app/com.teamwin.htcdumlock*");
1025 __system("cp /res/htcd/HTCDumlock.apk /data/app/com.teamwin.htcdumlock.apk");
1026 sync();
1027 ui_print("HTC Dumlock is installed.\n");
1028}
1029
1030void htc_dumlock_restore_original_boot(void)
1031{
1032 ui_print("Restoring original boot...\n");
1033 __system("htcdumlock restore");
1034 ui_print("Original boot restored.\n");
1035}
1036
1037void htc_dumlock_reflash_recovery_to_boot(void)
1038{
1039 ui_print("Reflashing recovery to boot...\n");
1040 __system("htcdumlock recovery noreboot");
1041 ui_print("Recovery is flashed to boot.\n");
1042}
1043
1044void check_and_run_script(const char* script_file, const char* display_name)
1045{
1046 // Check for and run startup script if script exists
1047 struct statfs st;
1048 if (statfs(script_file, &st) == 0) {
1049 ui_print("Running %s script...\n", display_name);
1050 char command[255];
1051 strcpy(command, "chmod 755 ");
1052 strcat(command, script_file);
1053 __system(command);
1054 __system(script_file);
1055 ui_print("\nFinished running %s script.\n", display_name);
1056 }
1057}
1058
1059int check_backup_name(int show_error) {
1060 // Check the backup name to ensure that it is the correct size and contains only valid characters
1061 // and that a backup with that name doesn't already exist
1062 char backup_name[MAX_BACKUP_NAME_LEN];
1063 char backup_loc[255], tw_image_dir[255];
1064 int copy_size = strlen(DataManager_GetStrValue(TW_BACKUP_NAME));
1065 int index, cur_char;
1066 struct statfs st;
1067
1068 // Check size
1069 if (copy_size > MAX_BACKUP_NAME_LEN) {
1070 if (show_error)
1071 LOGE("Backup name is too long.\n");
1072 return -2;
1073 }
1074
1075 // Check characters
1076 strncpy(backup_name, DataManager_GetStrValue(TW_BACKUP_NAME), copy_size);
1077 if (strcmp(backup_name, "0") == 0)
1078 return 0; // A "0" (zero) means to use the current timestamp for the backup name
1079 for (index=0; index<copy_size; index++) {
1080 cur_char = (int)backup_name[index];
1081 if ((cur_char >= 48 && cur_char <= 57) || (cur_char >= 65 && cur_char <= 91) || cur_char == 93 || cur_char == 95 || (cur_char >= 97 && cur_char <= 123) || cur_char == 125 || cur_char == 45 || cur_char == 46) {
1082 // These are valid characters
1083 // Numbers
1084 // Upper case letters
1085 // Lower case letters
1086 // and -_.{}[]
1087 } else {
1088 if (show_error)
1089 LOGE("Backup name '%s' contains invalid character: '%c'\n", backup_name, (char)cur_char);
1090 return -3;
1091 }
1092 }
1093
1094 // Check to make sure that a backup with this name doesn't already exist
1095 strcpy(backup_loc, DataManager_GetStrValue(TW_BACKUPS_FOLDER_VAR));
1096 sprintf(tw_image_dir,"%s/%s/.", backup_loc, backup_name);
1097 if (statfs(tw_image_dir, &st) == 0) {
1098 if (show_error)
1099 LOGE("A backup with this name already exists.\n");
1100 return -4;
1101 }
1102
1103 // No problems found, return 0
1104 return 0;
1105}
Dees_Troy7d15c252012-09-05 20:47:21 -04001106
1107static const char *COMMAND_FILE = "/cache/recovery/command";
1108static const char *INTENT_FILE = "/cache/recovery/intent";
1109static const char *LOG_FILE = "/cache/recovery/log";
1110static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
1111static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
1112static const char *CACHE_ROOT = "/cache";
1113static const char *SDCARD_ROOT = "/sdcard";
1114static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
1115static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
1116
1117// close a file, log an error if the error indicator is set
1118static void check_and_fclose(FILE *fp, const char *name) {
1119 fflush(fp);
1120 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
1121 fclose(fp);
1122}
1123
1124static void copy_log_file(const char* source, const char* destination, int append) {
1125 FILE *log = fopen_path(destination, append ? "a" : "w");
1126 if (log == NULL) {
1127 LOGE("Can't open %s\n", destination);
1128 } else {
1129 FILE *tmplog = fopen(source, "r");
1130 if (tmplog != NULL) {
1131 if (append) {
1132 fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write
1133 }
1134 char buf[4096];
1135 while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log);
1136 if (append) {
1137 tmplog_offset = ftell(tmplog);
1138 }
1139 check_and_fclose(tmplog, source);
1140 }
1141 check_and_fclose(log, destination);
1142 }
1143}
1144
1145// clear the recovery command and prepare to boot a (hopefully working) system,
1146// copy our log file to cache as well (for the system to read), and
1147// record any intent we were asked to communicate back to the system.
1148// this function is idempotent: call it as many times as you like.
1149void twfinish_recovery(const char *send_intent) {
1150 // By this point, we're ready to return to the main system...
1151 if (send_intent != NULL) {
1152 FILE *fp = fopen_path(INTENT_FILE, "w");
1153 if (fp == NULL) {
1154 LOGE("Can't open %s\n", INTENT_FILE);
1155 } else {
1156 fputs(send_intent, fp);
1157 check_and_fclose(fp, INTENT_FILE);
1158 }
1159 }
1160
1161 // Copy logs to cache so the system can find out what happened.
1162 copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
1163 copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
1164 copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
1165 chmod(LOG_FILE, 0600);
1166 chown(LOG_FILE, 1000, 1000); // system user
1167 chmod(LAST_LOG_FILE, 0640);
1168 chmod(LAST_INSTALL_FILE, 0644);
1169
1170 // Reset to normal system boot so recovery won't cycle indefinitely.
1171 struct bootloader_message boot;
1172 memset(&boot, 0, sizeof(boot));
1173 set_bootloader_message(&boot);
1174
1175 // Remove the command file, so recovery won't repeat indefinitely.
1176 if (ensure_path_mounted(COMMAND_FILE) != 0 ||
1177 (unlink(COMMAND_FILE) && errno != ENOENT)) {
1178 LOGW("Can't unlink %s\n", COMMAND_FILE);
1179 }
1180
1181 ensure_path_unmounted(CACHE_ROOT);
1182 sync(); // For good measure.
1183}
1184