blob: 9157e2397df3e00561a584defa300e74b57e08a0 [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 -0400306int TWtry_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
307 const ZipEntry* binary_entry =
308 mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
309 if (binary_entry == NULL) {
310 mzCloseZipArchive(zip);
Dees_Troy7d15c252012-09-05 20:47:21 -0400311 return INSTALL_CORRUPT;
312 }
Dees_Troy657c3092012-09-10 20:32:10 -0400313 const char* binary = "/tmp/update_binary";
314 unlink(binary);
315 int fd = creat(binary, 0755);
316 if (fd < 0) {
317 mzCloseZipArchive(zip);
318 LOGE("Can't make %s\n", binary);
319 return INSTALL_ERROR;
Dees_Troy7d15c252012-09-05 20:47:21 -0400320 }
Dees_Troy657c3092012-09-10 20:32:10 -0400321 bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
322 close(fd);
323 mzCloseZipArchive(zip);
Dees_Troy7d15c252012-09-05 20:47:21 -0400324
Dees_Troy657c3092012-09-10 20:32:10 -0400325 if (!ok) {
326 LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
327 return INSTALL_ERROR;
328 }
Dees_Troy7d15c252012-09-05 20:47:21 -0400329
Dees_Troy657c3092012-09-10 20:32:10 -0400330 int pipefd[2];
331 pipe(pipefd);
Dees_Troy7d15c252012-09-05 20:47:21 -0400332
Dees_Troy657c3092012-09-10 20:32:10 -0400333 // When executing the update binary contained in the package, the
334 // arguments passed are:
335 //
336 // - the version number for this interface
337 //
338 // - an fd to which the program can write in order to update the
339 // progress bar. The program can write single-line commands:
340 //
341 // progress <frac> <secs>
342 // fill up the next <frac> part of of the progress bar
343 // over <secs> seconds. If <secs> is zero, use
344 // set_progress commands to manually control the
345 // progress of this segment of the bar
346 //
347 // set_progress <frac>
348 // <frac> should be between 0.0 and 1.0; sets the
349 // progress bar within the segment defined by the most
350 // recent progress command.
351 //
352 // firmware <"hboot"|"radio"> <filename>
353 // arrange to install the contents of <filename> in the
354 // given partition on reboot.
355 //
356 // (API v2: <filename> may start with "PACKAGE:" to
357 // indicate taking a file from the OTA package.)
358 //
359 // (API v3: this command no longer exists.)
360 //
361 // ui_print <string>
362 // display <string> on the screen.
363 //
364 // - the name of the package zip file.
365 //
366
367 const char** args = (const char**)malloc(sizeof(char*) * 5);
368 args[0] = binary;
369 args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
370 char* temp = (char*)malloc(10);
371 sprintf(temp, "%d", pipefd[1]);
372 args[2] = temp;
373 args[3] = (char*)path;
374 args[4] = NULL;
375
376 pid_t pid = fork();
377 if (pid == 0) {
378 close(pipefd[0]);
379 execv(binary, (char* const*)args);
380 fprintf(stdout, "E:Can't run %s (error)\n", binary);
381 _exit(-1);
382 }
383 close(pipefd[1]);
384 *wipe_cache = 0;
385
386 char buffer[1024];
387 FILE* from_child = fdopen(pipefd[0], "r");
388 LOGI("8\n");
389 while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
390 char* command = strtok(buffer, " \n");
391 if (command == NULL) {
392 continue;
393 } else if (strcmp(command, "progress") == 0) {
394 char* fraction_s = strtok(NULL, " \n");
395 char* seconds_s = strtok(NULL, " \n");
396
397 float fraction = strtof(fraction_s, NULL);
398 int seconds = strtol(seconds_s, NULL, 10);
399
400 //ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);
401 } else if (strcmp(command, "set_progress") == 0) {
402 char* fraction_s = strtok(NULL, " \n");
403 float fraction = strtof(fraction_s, NULL);
404 //ui->SetProgress(fraction);
405 } else if (strcmp(command, "ui_print") == 0) {
406 char* str = strtok(NULL, "\n");
407 if (str) {
408 //ui->Print("%s", str);
409 } else {
410 //ui->Print("\n");
411 }
412 } else if (strcmp(command, "wipe_cache") == 0) {
413 *wipe_cache = 1;
414 } else if (strcmp(command, "clear_display") == 0) {
415 //ui->SetBackground(RecoveryUI::NONE);
416 } else {
417 LOGE("unknown command [%s]\n", command);
418 }
419 }
420 fclose(from_child);
421
422 int status;
423 waitpid(pid, &status, 0);
424 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
425 LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
426 return INSTALL_ERROR;
427 }
428 return INSTALL_SUCCESS;
429}
430
431// Look for an RSA signature embedded in the .ZIP file comment given
432// the path to the zip. Verify it matches one of the given public
433// keys.
434//
435// Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered
436// or no key matches the signature).
437
438int TWverify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys) {
439 //ui->SetProgress(0.0);
440
441 FILE* f = fopen(path, "rb");
442 if (f == NULL) {
443 LOGE("failed to open %s (%s)\n", path, strerror(errno));
444 return VERIFY_FAILURE;
445 }
446
447 // An archive with a whole-file signature will end in six bytes:
448 //
449 // (2-byte signature start) $ff $ff (2-byte comment size)
450 //
451 // (As far as the ZIP format is concerned, these are part of the
452 // archive comment.) We start by reading this footer, this tells
453 // us how far back from the end we have to start reading to find
454 // the whole comment.
455
456#define FOOTER_SIZE 6
457
458 if (fseek(f, -FOOTER_SIZE, SEEK_END) != 0) {
459 LOGE("failed to seek in %s (%s)\n", path, strerror(errno));
460 fclose(f);
461 return VERIFY_FAILURE;
462 }
463
464 unsigned char footer[FOOTER_SIZE];
465 if (fread(footer, 1, FOOTER_SIZE, f) != FOOTER_SIZE) {
466 LOGE("failed to read footer from %s (%s)\n", path, strerror(errno));
467 fclose(f);
468 return VERIFY_FAILURE;
469 }
470
471 if (footer[2] != 0xff || footer[3] != 0xff) {
472 fclose(f);
473 return VERIFY_FAILURE;
474 }
475
476 size_t comment_size = footer[4] + (footer[5] << 8);
477 size_t signature_start = footer[0] + (footer[1] << 8);
478 LOGI("comment is %d bytes; signature %d bytes from end\n",
479 comment_size, signature_start);
480
481 if (signature_start - FOOTER_SIZE < RSANUMBYTES) {
482 // "signature" block isn't big enough to contain an RSA block.
483 LOGE("signature is too short\n");
484 fclose(f);
485 return VERIFY_FAILURE;
486 }
487
488#define EOCD_HEADER_SIZE 22
489
490 // The end-of-central-directory record is 22 bytes plus any
491 // comment length.
492 size_t eocd_size = comment_size + EOCD_HEADER_SIZE;
493
494 if (fseek(f, -eocd_size, SEEK_END) != 0) {
495 LOGE("failed to seek in %s (%s)\n", path, strerror(errno));
496 fclose(f);
497 return VERIFY_FAILURE;
498 }
499
500 // Determine how much of the file is covered by the signature.
501 // This is everything except the signature data and length, which
502 // includes all of the EOCD except for the comment length field (2
503 // bytes) and the comment data.
504 size_t signed_len = ftell(f) + EOCD_HEADER_SIZE - 2;
505
506 unsigned char* eocd = (unsigned char*)malloc(eocd_size);
507 if (eocd == NULL) {
508 LOGE("malloc for EOCD record failed\n");
509 fclose(f);
510 return VERIFY_FAILURE;
511 }
512 if (fread(eocd, 1, eocd_size, f) != eocd_size) {
513 LOGE("failed to read eocd from %s (%s)\n", path, strerror(errno));
514 fclose(f);
515 return VERIFY_FAILURE;
516 }
517
518 // If this is really is the EOCD record, it will begin with the
519 // magic number $50 $4b $05 $06.
520 if (eocd[0] != 0x50 || eocd[1] != 0x4b ||
521 eocd[2] != 0x05 || eocd[3] != 0x06) {
522 LOGE("signature length doesn't match EOCD marker\n");
523 fclose(f);
524 return VERIFY_FAILURE;
525 }
526
527 size_t i;
528 for (i = 4; i < eocd_size-3; ++i) {
529 if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b &&
530 eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
531 // if the sequence $50 $4b $05 $06 appears anywhere after
532 // the real one, minzip will find the later (wrong) one,
533 // which could be exploitable. Fail verification if
534 // this sequence occurs anywhere after the real one.
535 LOGE("EOCD marker occurs after start of EOCD\n");
536 fclose(f);
537 return VERIFY_FAILURE;
538 }
539 }
540
541#define BUFFER_SIZE 4096
542
543 SHA_CTX ctx;
544 SHA_init(&ctx);
545 unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);
546 if (buffer == NULL) {
547 LOGE("failed to alloc memory for sha1 buffer\n");
548 fclose(f);
549 return VERIFY_FAILURE;
550 }
551
552 double frac = -1.0;
553 size_t so_far = 0;
554 fseek(f, 0, SEEK_SET);
555 while (so_far < signed_len) {
556 size_t size = BUFFER_SIZE;
557 if (signed_len - so_far < size) size = signed_len - so_far;
558 if (fread(buffer, 1, size, f) != size) {
559 LOGE("failed to read data from %s (%s)\n", path, strerror(errno));
560 fclose(f);
561 return VERIFY_FAILURE;
562 }
563 SHA_update(&ctx, buffer, size);
564 so_far += size;
565 double f = so_far / (double)signed_len;
566 if (f > frac + 0.02 || size == so_far) {
567 //ui->SetProgress(f);
568 frac = f;
569 }
570 }
571 fclose(f);
572 free(buffer);
573
574 const uint8_t* sha1 = SHA_final(&ctx);
575 for (i = 0; i < numKeys; ++i) {
576 // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
577 // the signing tool appends after the signature itself.
578 if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES,
579 RSANUMBYTES, sha1)) {
580 LOGI("whole-file signature verified against key %d\n", i);
581 free(eocd);
582 return VERIFY_SUCCESS;
583 }
584 }
585 free(eocd);
586 LOGE("failed to verify whole-file signature\n");
587 return VERIFY_FAILURE;
588}
589
590// Reads a file containing one or more public keys as produced by
591// DumpPublicKey: this is an RSAPublicKey struct as it would appear
592// as a C source literal, eg:
593//
594// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
595//
596// (Note that the braces and commas in this example are actual
597// characters the parser expects to find in the file; the ellipses
598// indicate more numbers omitted from this example.)
599//
600// The file may contain multiple keys in this format, separated by
601// commas. The last key must not be followed by a comma.
602//
603// Returns NULL if the file failed to parse, or if it contain zero keys.
604static RSAPublicKey*
605TWload_keys(const char* filename, int* numKeys) {
606 RSAPublicKey* out = NULL;
607 *numKeys = 0;
608
609 FILE* f = fopen(filename, "r");
610 if (f == NULL) {
611 LOGE("opening %s: ERROR\n", filename);
612 goto exit;
613 }
614
615 {
616 int i;
617 bool done = false;
618 while (!done) {
619 ++*numKeys;
620 out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
621 RSAPublicKey* key = out + (*numKeys - 1);
622 if (fscanf(f, " { %i , 0x%x , { %u",
623 &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
624 goto exit;
625 }
626 if (key->len != RSANUMWORDS) {
627 LOGE("key length (%d) does not match expected size\n", key->len);
628 goto exit;
629 }
630 for (i = 1; i < key->len; ++i) {
631 if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
632 }
633 if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
634 for (i = 1; i < key->len; ++i) {
635 if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
636 }
637 fscanf(f, " } } ");
638
639 // if the line ends in a comma, this file has more keys.
640 switch (fgetc(f)) {
641 case ',':
642 // more keys to come.
643 break;
644
645 case EOF:
646 done = true;
647 break;
648
649 default:
650 LOGE("unexpected character between keys\n");
651 goto exit;
652 }
653 }
654 }
655
656 fclose(f);
657 return out;
658
659exit:
660 if (f) fclose(f);
661 free(out);
662 *numKeys = 0;
663 return NULL;
664}
665
666int TWinstall_zip(const char* path, int* wipe_cache) {
667 int err;
668
669 if (DataManager_GetIntValue(TW_SIGNED_ZIP_VERIFY_VAR)) {
670 int numKeys;
671 RSAPublicKey* loadedKeys = TWload_keys(PUBLIC_KEYS_FILE, &numKeys);
672 if (loadedKeys == NULL) {
673 LOGE("Failed to load keys\n");
674 return -1;
675 }
676 LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
677
678 // Give verification half the progress bar...
679 //ui->Print("Verifying update package...\n");
680 //ui->SetProgressType(RecoveryUI::DETERMINATE);
681 //ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME);
682
683 err = TWverify_file(path, loadedKeys, numKeys);
684 free(loadedKeys);
685 LOGI("verify_file returned %d\n", err);
686 if (err != VERIFY_SUCCESS) {
687 LOGE("signature verification failed\n");
688 return -1;
689 }
690 }
691 /* Try to open the package.
Dees_Troy7d15c252012-09-05 20:47:21 -0400692 */
693 ZipArchive zip;
694 err = mzOpenZipArchive(path, &zip);
695 if (err != 0) {
696 LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
697 return INSTALL_CORRUPT;
698 }
699
700 /* Verify and install the contents of the package.
701 */
Dees_Troy657c3092012-09-10 20:32:10 -0400702 //ui->Print("Installing update...\n");
703 return TWtry_update_binary(path, &zip, wipe_cache);
Dees_Troy51a0e822012-09-05 15:24:24 -0400704}
705
706//partial kangbang from system/vold
707#ifndef CUSTOM_LUN_FILE
708#define CUSTOM_LUN_FILE "/sys/devices/platform/usb_mass_storage/lun%d/file"
709#endif
710
711int usb_storage_enable(void)
712{
713 int fd;
714 char lun_file[255];
715
716 if (DataManager_GetIntValue(TW_HAS_DUAL_STORAGE) == 1 && DataManager_GetIntValue(TW_HAS_DATA_MEDIA) == 0) {
717 Volume *vol = volume_for_path(DataManager_GetSettingsStoragePath());
718 if (!vol)
719 {
720 LOGE("Unable to locate volume information.");
721 return -1;
722 }
723
724 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
725
726 if ((fd = open(lun_file, O_WRONLY)) < 0)
727 {
728 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
729 return -1;
730 }
731
732 if ((write(fd, vol->device, strlen(vol->device)) < 0) &&
733 (!vol->device2 || (write(fd, vol->device, strlen(vol->device2)) < 0))) {
734 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
735 close(fd);
736 return -1;
737 }
738 close(fd);
739
740 Volume *vol2 = volume_for_path(DataManager_GetStrValue(TW_EXTERNAL_PATH));
741 if (!vol)
742 {
743 LOGE("Unable to locate volume information.\n");
744 return -1;
745 }
746
747 sprintf(lun_file, CUSTOM_LUN_FILE, 1);
748
749 if ((fd = open(lun_file, O_WRONLY)) < 0)
750 {
751 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
752 return -1;
753 }
754
755 if ((write(fd, vol2->device, strlen(vol2->device)) < 0) &&
756 (!vol2->device2 || (write(fd, vol2->device, strlen(vol2->device2)) < 0))) {
757 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
758 close(fd);
759 return -1;
760 }
761 close(fd);
762 } else {
763 if (DataManager_GetIntValue(TW_HAS_DATA_MEDIA) == 0)
764 strcpy(lun_file, DataManager_GetCurrentStoragePath());
765 else
766 strcpy(lun_file, DataManager_GetStrValue(TW_EXTERNAL_PATH));
767
768 Volume *vol = volume_for_path(lun_file);
769 if (!vol)
770 {
771 LOGE("Unable to locate volume information.\n");
772 return -1;
773 }
774
775 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
776
777 if ((fd = open(lun_file, O_WRONLY)) < 0)
778 {
779 LOGE("Unable to open ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
780 return -1;
781 }
782
783 if ((write(fd, vol->device, strlen(vol->device)) < 0) &&
784 (!vol->device2 || (write(fd, vol->device, strlen(vol->device2)) < 0))) {
785 LOGE("Unable to write to ums lunfile '%s': (%s)\n", lun_file, strerror(errno));
786 close(fd);
787 return -1;
788 }
789 close(fd);
790 }
791 return 0;
792}
793
794int usb_storage_disable(void)
795{
796 int fd, index;
797 char lun_file[255];
798
799 for (index=0; index<2; index++) {
800 sprintf(lun_file, CUSTOM_LUN_FILE, index);
801
802 if ((fd = open(lun_file, O_WRONLY)) < 0)
803 {
804 if (index == 0)
805 LOGE("Unable to open ums lunfile '%s': (%s)", lun_file, strerror(errno));
806 return -1;
807 }
808
809 char ch = 0;
810 if (write(fd, &ch, 1) < 0)
811 {
812 if (index == 0)
813 LOGE("Unable to write to ums lunfile '%s': (%s)", lun_file, strerror(errno));
814 close(fd);
815 return -1;
816 }
817
818 close(fd);
819 }
820 return 0;
821}
822
823void wipe_dalvik_cache()
824{
825 //ui_set_background(BACKGROUND_ICON_WIPE);
826 ensure_path_mounted("/data");
827 ensure_path_mounted("/cache");
828 ui_print("\n-- Wiping Dalvik Cache Directories...\n");
829 __system("rm -rf /data/dalvik-cache");
830 ui_print("Cleaned: /data/dalvik-cache...\n");
831 __system("rm -rf /cache/dalvik-cache");
832 ui_print("Cleaned: /cache/dalvik-cache...\n");
833 __system("rm -rf /cache/dc");
834 ui_print("Cleaned: /cache/dc\n");
835
836 struct stat st;
837 LOGE("TODO: Re-implement wipe dalvik into Partition Manager!\n");
838 if (1) //if (0 != stat(sde.blk, &st))
839 {
840 ui_print("/sd-ext not present, skipping\n");
841 } else {
842 __system("mount /sd-ext");
843 LOGI("Mounting /sd-ext\n");
844 if (stat("/sd-ext/dalvik-cache",&st) == 0)
845 {
846 __system("rm -rf /sd-ext/dalvik-cache");
847 ui_print("Cleaned: /sd-ext/dalvik-cache...\n");
848 }
849 }
850 ensure_path_unmounted("/data");
851 ui_print("-- Dalvik Cache Directories Wipe Complete!\n\n");
852 //ui_set_background(BACKGROUND_ICON_MAIN);
853 //if (!ui_text_visible()) return;
854}
855
856// BATTERY STATS
857void wipe_battery_stats()
858{
859 ensure_path_mounted("/data");
860 struct stat st;
861 if (0 != stat("/data/system/batterystats.bin", &st))
862 {
863 ui_print("No Battery Stats Found. No Need To Wipe.\n");
864 } else {
865 //ui_set_background(BACKGROUND_ICON_WIPE);
866 remove("/data/system/batterystats.bin");
867 ui_print("Cleared: Battery Stats...\n");
868 ensure_path_unmounted("/data");
869 }
870}
871
872// ROTATION SETTINGS
873void wipe_rotate_data()
874{
875 //ui_set_background(BACKGROUND_ICON_WIPE);
876 ensure_path_mounted("/data");
877 __system("rm -r /data/misc/akmd*");
878 __system("rm -r /data/misc/rild*");
879 ui_print("Cleared: Rotatation Data...\n");
880 ensure_path_unmounted("/data");
881}
882
883void fix_perms()
884{
885 ensure_path_mounted("/data");
886 ensure_path_mounted("/system");
887 //ui_show_progress(1,30);
888 ui_print("\n-- Fixing Permissions\n");
889 ui_print("This may take a few minutes.\n");
890 __system("./sbin/fix_permissions.sh");
891 ui_print("-- Done.\n\n");
892 //ui_reset_progress();
893}
894
895int get_battery_level(void)
896{
897 static int lastVal = -1;
898 static time_t nextSecCheck = 0;
899
900 struct timeval curTime;
901 gettimeofday(&curTime, NULL);
902 if (curTime.tv_sec > nextSecCheck)
903 {
904 char cap_s[4];
905 FILE * cap = fopen("/sys/class/power_supply/battery/capacity","rt");
906 if (cap)
907 {
908 fgets(cap_s, 4, cap);
909 fclose(cap);
910 lastVal = atoi(cap_s);
911 if (lastVal > 100) lastVal = 101;
912 if (lastVal < 0) lastVal = 0;
913 }
914 nextSecCheck = curTime.tv_sec + 60;
915 }
916 return lastVal;
917}
918
Dees_Troy51a0e822012-09-05 15:24:24 -0400919void update_tz_environment_variables() {
920 setenv("TZ", DataManager_GetStrValue(TW_TIME_ZONE_VAR), 1);
921 tzset();
922}
923
924void 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)
925{
926 ui_print("%s", str1);
927 //ui_clear_key_queue();
928 ui_print("\nPress Power to confirm,");
929 ui_print("\nany other key to abort.\n");
930 int confirm;
931 /*if (request_confirm) // this option is used to skip the confirmation when the gui is in use
932 confirm = ui_wait_key();
933 else*/
934 confirm = KEY_POWER;
935
936 if (confirm == BTN_MOUSE || confirm == KEY_POWER || confirm == SELECT_ITEM) {
937 ui_print("%s", str2);
938 pid_t pid = fork();
939 if (pid == 0) {
940 char *args[] = { "/sbin/sh", "-c", (char*)str3, "1>&2", NULL };
941 execv("/sbin/sh", args);
942 fprintf(stderr, str4, strerror(errno));
943 _exit(-1);
944 }
945 int status;
946 while (waitpid(pid, &status, WNOHANG) == 0) {
947 ui_print(".");
948 sleep(1);
949 }
950 ui_print("\n");
951 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
952 ui_print("%s", str5);
953 } else {
954 ui_print("%s", str6);
955 }
956 } else {
957 ui_print("%s", str7);
958 }
959 //if (!ui_text_visible()) return;
960}
961
962void install_htc_dumlock(void)
963{
964 struct statfs fs1, fs2;
965 int need_libs = 0;
966
967 ui_print("Installing HTC Dumlock to system...\n");
968 ensure_path_mounted("/system");
969 __system("cp /res/htcd/htcdumlocksys /system/bin/htcdumlock && chmod 755 /system/bin/htcdumlock");
970 if (statfs("/system/bin/flash_image", &fs1) != 0) {
971 ui_print("Installing flash_image...\n");
972 __system("cp /res/htcd/flash_imagesys /system/bin/flash_image && chmod 755 /system/bin/flash_image");
973 need_libs = 1;
974 } else
975 ui_print("flash_image is already installed, skipping...\n");
976 if (statfs("/system/bin/dump_image", &fs2) != 0) {
977 ui_print("Installing dump_image...\n");
978 __system("cp /res/htcd/dump_imagesys /system/bin/dump_image && chmod 755 /system/bin/dump_image");
979 need_libs = 1;
980 } else
981 ui_print("dump_image is already installed, skipping...\n");
982 if (need_libs) {
983 ui_print("Installing libs needed for flash_image and dump_image...\n");
984 __system("cp /res/htcd/libbmlutils.so /system/lib && chmod 755 /system/lib/libbmlutils.so");
985 __system("cp /res/htcd/libflashutils.so /system/lib && chmod 755 /system/lib/libflashutils.so");
986 __system("cp /res/htcd/libmmcutils.so /system/lib && chmod 755 /system/lib/libmmcutils.so");
987 __system("cp /res/htcd/libmtdutils.so /system/lib && chmod 755 /system/lib/libmtdutils.so");
988 }
989 ui_print("Installing HTC Dumlock app...\n");
990 ensure_path_mounted("/data");
991 mkdir("/data/app", 0777);
992 __system("rm /data/app/com.teamwin.htcdumlock*");
993 __system("cp /res/htcd/HTCDumlock.apk /data/app/com.teamwin.htcdumlock.apk");
994 sync();
995 ui_print("HTC Dumlock is installed.\n");
996}
997
998void htc_dumlock_restore_original_boot(void)
999{
1000 ui_print("Restoring original boot...\n");
1001 __system("htcdumlock restore");
1002 ui_print("Original boot restored.\n");
1003}
1004
1005void htc_dumlock_reflash_recovery_to_boot(void)
1006{
1007 ui_print("Reflashing recovery to boot...\n");
1008 __system("htcdumlock recovery noreboot");
1009 ui_print("Recovery is flashed to boot.\n");
1010}
1011
1012void check_and_run_script(const char* script_file, const char* display_name)
1013{
1014 // Check for and run startup script if script exists
1015 struct statfs st;
1016 if (statfs(script_file, &st) == 0) {
1017 ui_print("Running %s script...\n", display_name);
1018 char command[255];
1019 strcpy(command, "chmod 755 ");
1020 strcat(command, script_file);
1021 __system(command);
1022 __system(script_file);
1023 ui_print("\nFinished running %s script.\n", display_name);
1024 }
1025}
1026
1027int check_backup_name(int show_error) {
1028 // Check the backup name to ensure that it is the correct size and contains only valid characters
1029 // and that a backup with that name doesn't already exist
1030 char backup_name[MAX_BACKUP_NAME_LEN];
1031 char backup_loc[255], tw_image_dir[255];
1032 int copy_size = strlen(DataManager_GetStrValue(TW_BACKUP_NAME));
1033 int index, cur_char;
1034 struct statfs st;
1035
1036 // Check size
1037 if (copy_size > MAX_BACKUP_NAME_LEN) {
1038 if (show_error)
1039 LOGE("Backup name is too long.\n");
1040 return -2;
1041 }
1042
1043 // Check characters
1044 strncpy(backup_name, DataManager_GetStrValue(TW_BACKUP_NAME), copy_size);
1045 if (strcmp(backup_name, "0") == 0)
1046 return 0; // A "0" (zero) means to use the current timestamp for the backup name
1047 for (index=0; index<copy_size; index++) {
1048 cur_char = (int)backup_name[index];
1049 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) {
1050 // These are valid characters
1051 // Numbers
1052 // Upper case letters
1053 // Lower case letters
1054 // and -_.{}[]
1055 } else {
1056 if (show_error)
1057 LOGE("Backup name '%s' contains invalid character: '%c'\n", backup_name, (char)cur_char);
1058 return -3;
1059 }
1060 }
1061
1062 // Check to make sure that a backup with this name doesn't already exist
1063 strcpy(backup_loc, DataManager_GetStrValue(TW_BACKUPS_FOLDER_VAR));
1064 sprintf(tw_image_dir,"%s/%s/.", backup_loc, backup_name);
1065 if (statfs(tw_image_dir, &st) == 0) {
1066 if (show_error)
1067 LOGE("A backup with this name already exists.\n");
1068 return -4;
1069 }
1070
1071 // No problems found, return 0
1072 return 0;
1073}
Dees_Troy7d15c252012-09-05 20:47:21 -04001074
1075static const char *COMMAND_FILE = "/cache/recovery/command";
1076static const char *INTENT_FILE = "/cache/recovery/intent";
1077static const char *LOG_FILE = "/cache/recovery/log";
1078static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
1079static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
1080static const char *CACHE_ROOT = "/cache";
1081static const char *SDCARD_ROOT = "/sdcard";
1082static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
1083static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
1084
1085// close a file, log an error if the error indicator is set
1086static void check_and_fclose(FILE *fp, const char *name) {
1087 fflush(fp);
1088 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
1089 fclose(fp);
1090}
1091
1092static void copy_log_file(const char* source, const char* destination, int append) {
1093 FILE *log = fopen_path(destination, append ? "a" : "w");
1094 if (log == NULL) {
1095 LOGE("Can't open %s\n", destination);
1096 } else {
1097 FILE *tmplog = fopen(source, "r");
1098 if (tmplog != NULL) {
1099 if (append) {
1100 fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write
1101 }
1102 char buf[4096];
1103 while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log);
1104 if (append) {
1105 tmplog_offset = ftell(tmplog);
1106 }
1107 check_and_fclose(tmplog, source);
1108 }
1109 check_and_fclose(log, destination);
1110 }
1111}
1112
1113// clear the recovery command and prepare to boot a (hopefully working) system,
1114// copy our log file to cache as well (for the system to read), and
1115// record any intent we were asked to communicate back to the system.
1116// this function is idempotent: call it as many times as you like.
1117void twfinish_recovery(const char *send_intent) {
1118 // By this point, we're ready to return to the main system...
1119 if (send_intent != NULL) {
1120 FILE *fp = fopen_path(INTENT_FILE, "w");
1121 if (fp == NULL) {
1122 LOGE("Can't open %s\n", INTENT_FILE);
1123 } else {
1124 fputs(send_intent, fp);
1125 check_and_fclose(fp, INTENT_FILE);
1126 }
1127 }
1128
1129 // Copy logs to cache so the system can find out what happened.
1130 copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
1131 copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
1132 copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
1133 chmod(LOG_FILE, 0600);
1134 chown(LOG_FILE, 1000, 1000); // system user
1135 chmod(LAST_LOG_FILE, 0640);
1136 chmod(LAST_INSTALL_FILE, 0644);
1137
1138 // Reset to normal system boot so recovery won't cycle indefinitely.
1139 struct bootloader_message boot;
1140 memset(&boot, 0, sizeof(boot));
1141 set_bootloader_message(&boot);
1142
1143 // Remove the command file, so recovery won't repeat indefinitely.
1144 if (ensure_path_mounted(COMMAND_FILE) != 0 ||
1145 (unlink(COMMAND_FILE) && errno != ENOENT)) {
1146 LOGW("Can't unlink %s\n", COMMAND_FILE);
1147 }
1148
1149 ensure_path_unmounted(CACHE_ROOT);
1150 sync(); // For good measure.
1151}
1152