1 /* 2 * Copyright (C) 2007 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 <ctype.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <getopt.h> 21 #include <limits.h> 22 #include <linux/input.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <sys/reboot.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 29 #include <time.h> 30 #include <unistd.h> 31 #include <dirent.h> 32 33 #include "bootloader.h" 34 #include "common.h" 35 #include "cutils/properties.h" 36 #include "install.h" 37 #include "minui/minui.h" 38 #include "minzip/DirUtil.h" 39 #include "roots.h" 40 #include "recovery_ui.h" 41 #include "encryptedfs_provisioning.h" 42 43 static const struct option OPTIONS[] = { 44 { "send_intent", required_argument, NULL, 's' }, 45 { "update_package", required_argument, NULL, 'u' }, 46 { "wipe_data", no_argument, NULL, 'w' }, 47 { "wipe_cache", no_argument, NULL, 'c' }, 48 { "set_encrypted_filesystems", required_argument, NULL, 'e' }, 49 { "show_text", no_argument, NULL, 't' }, 50 { NULL, 0, NULL, 0 }, 51 }; 52 53 static const char *COMMAND_FILE = "/cache/recovery/command"; 54 static const char *INTENT_FILE = "/cache/recovery/intent"; 55 static const char *LOG_FILE = "/cache/recovery/log"; 56 static const char *LAST_LOG_FILE = "/cache/recovery/last_log"; 57 static const char *SDCARD_ROOT = "/sdcard"; 58 static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; 59 static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; 60 61 /* 62 * The recovery tool communicates with the main system through /cache files. 63 * /cache/recovery/command - INPUT - command line for tool, one arg per line 64 * /cache/recovery/log - OUTPUT - combined log file from recovery run(s) 65 * /cache/recovery/intent - OUTPUT - intent that was passed in 66 * 67 * The arguments which may be supplied in the recovery.command file: 68 * --send_intent=anystring - write the text out to recovery.intent 69 * --update_package=path - verify install an OTA package file 70 * --wipe_data - erase user data (and cache), then reboot 71 * --wipe_cache - wipe cache (but not user data), then reboot 72 * --set_encrypted_filesystem=on|off - enables / diasables encrypted fs 73 * 74 * After completing, we remove /cache/recovery/command and reboot. 75 * Arguments may also be supplied in the bootloader control block (BCB). 76 * These important scenarios must be safely restartable at any point: 77 * 78 * FACTORY RESET 79 * 1. user selects "factory reset" 80 * 2. main system writes "--wipe_data" to /cache/recovery/command 81 * 3. main system reboots into recovery 82 * 4. get_args() writes BCB with "boot-recovery" and "--wipe_data" 83 * -- after this, rebooting will restart the erase -- 84 * 5. erase_volume() reformats /data 85 * 6. erase_volume() reformats /cache 86 * 7. finish_recovery() erases BCB 87 * -- after this, rebooting will restart the main system -- 88 * 8. main() calls reboot() to boot main system 89 * 90 * OTA INSTALL 91 * 1. main system downloads OTA package to /cache/some-filename.zip 92 * 2. main system writes "--update_package=/cache/some-filename.zip" 93 * 3. main system reboots into recovery 94 * 4. get_args() writes BCB with "boot-recovery" and "--update_package=..." 95 * -- after this, rebooting will attempt to reinstall the update -- 96 * 5. install_package() attempts to install the update 97 * NOTE: the package install must itself be restartable from any point 98 * 6. finish_recovery() erases BCB 99 * -- after this, rebooting will (try to) restart the main system -- 100 * 7. ** if install failed ** 101 * 7a. prompt_and_wait() shows an error icon and waits for the user 102 * 7b; the user reboots (pulling the battery, etc) into the main system 103 * 8. main() calls maybe_install_firmware_update() 104 * ** if the update contained radio/hboot firmware **: 105 * 8a. m_i_f_u() writes BCB with "boot-recovery" and "--wipe_cache" 106 * -- after this, rebooting will reformat cache & restart main system -- 107 * 8b. m_i_f_u() writes firmware image into raw cache partition 108 * 8c. m_i_f_u() writes BCB with "update-radio/hboot" and "--wipe_cache" 109 * -- after this, rebooting will attempt to reinstall firmware -- 110 * 8d. bootloader tries to flash firmware 111 * 8e. bootloader writes BCB with "boot-recovery" (keeping "--wipe_cache") 112 * -- after this, rebooting will reformat cache & restart main system -- 113 * 8f. erase_volume() reformats /cache 114 * 8g. finish_recovery() erases BCB 115 * -- after this, rebooting will (try to) restart the main system -- 116 * 9. main() calls reboot() to boot main system 117 * 118 * SECURE FILE SYSTEMS ENABLE/DISABLE 119 * 1. user selects "enable encrypted file systems" 120 * 2. main system writes "--set_encrypted_filesystems=on|off" to 121 * /cache/recovery/command 122 * 3. main system reboots into recovery 123 * 4. get_args() writes BCB with "boot-recovery" and 124 * "--set_encrypted_filesystems=on|off" 125 * -- after this, rebooting will restart the transition -- 126 * 5. read_encrypted_fs_info() retrieves encrypted file systems settings from /data 127 * Settings include: property to specify the Encrypted FS istatus and 128 * FS encryption key if enabled (not yet implemented) 129 * 6. erase_volume() reformats /data 130 * 7. erase_volume() reformats /cache 131 * 8. restore_encrypted_fs_info() writes required encrypted file systems settings to /data 132 * Settings include: property to specify the Encrypted FS status and 133 * FS encryption key if enabled (not yet implemented) 134 * 9. finish_recovery() erases BCB 135 * -- after this, rebooting will restart the main system -- 136 * 10. main() calls reboot() to boot main system 137 */ 138 139 static const int MAX_ARG_LENGTH = 4096; 140 static const int MAX_ARGS = 100; 141 142 // open a given path, mounting partitions as necessary 143 static FILE* 144 fopen_path(const char *path, const char *mode) { 145 if (ensure_path_mounted(path) != 0) { 146 LOGE("Can't mount %s\n", path); 147 return NULL; 148 } 149 150 // When writing, try to create the containing directory, if necessary. 151 // Use generous permissions, the system (init.rc) will reset them. 152 if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1); 153 154 FILE *fp = fopen(path, mode); 155 return fp; 156 } 157 158 // close a file, log an error if the error indicator is set 159 static void 160 check_and_fclose(FILE *fp, const char *name) { 161 fflush(fp); 162 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno)); 163 fclose(fp); 164 } 165 166 // command line args come from, in decreasing precedence: 167 // - the actual command line 168 // - the bootloader control block (one per line, after "recovery") 169 // - the contents of COMMAND_FILE (one per line) 170 static void 171 get_args(int *argc, char ***argv) { 172 struct bootloader_message boot; 173 memset(&boot, 0, sizeof(boot)); 174 get_bootloader_message(&boot); // this may fail, leaving a zeroed structure 175 176 if (boot.command[0] != 0 && boot.command[0] != 255) { 177 LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command); 178 } 179 180 if (boot.status[0] != 0 && boot.status[0] != 255) { 181 LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status); 182 } 183 184 // --- if arguments weren't supplied, look in the bootloader control block 185 if (*argc <= 1) { 186 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination 187 const char *arg = strtok(boot.recovery, "\n"); 188 if (arg != NULL && !strcmp(arg, "recovery")) { 189 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS); 190 (*argv)[0] = strdup(arg); 191 for (*argc = 1; *argc < MAX_ARGS; ++*argc) { 192 if ((arg = strtok(NULL, "\n")) == NULL) break; 193 (*argv)[*argc] = strdup(arg); 194 } 195 LOGI("Got arguments from boot message\n"); 196 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) { 197 LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery); 198 } 199 } 200 201 // --- if that doesn't work, try the command file 202 if (*argc <= 1) { 203 FILE *fp = fopen_path(COMMAND_FILE, "r"); 204 if (fp != NULL) { 205 char *argv0 = (*argv)[0]; 206 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS); 207 (*argv)[0] = argv0; // use the same program name 208 209 char buf[MAX_ARG_LENGTH]; 210 for (*argc = 1; *argc < MAX_ARGS; ++*argc) { 211 if (!fgets(buf, sizeof(buf), fp)) break; 212 (*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline. 213 } 214 215 check_and_fclose(fp, COMMAND_FILE); 216 LOGI("Got arguments from %s\n", COMMAND_FILE); 217 } 218 } 219 220 // --> write the arguments we have back into the bootloader control block 221 // always boot into recovery after this (until finish_recovery() is called) 222 strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); 223 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); 224 int i; 225 for (i = 1; i < *argc; ++i) { 226 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery)); 227 strlcat(boot.recovery, "\n", sizeof(boot.recovery)); 228 } 229 set_bootloader_message(&boot); 230 } 231 232 static void 233 set_sdcard_update_bootloader_message() { 234 struct bootloader_message boot; 235 memset(&boot, 0, sizeof(boot)); 236 strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); 237 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); 238 set_bootloader_message(&boot); 239 } 240 241 // How much of the temp log we have copied to the copy in cache. 242 static long tmplog_offset = 0; 243 244 static void 245 copy_log_file(const char* destination, int append) { 246 FILE *log = fopen_path(destination, append ? "a" : "w"); 247 if (log == NULL) { 248 LOGE("Can't open %s\n", destination); 249 } else { 250 FILE *tmplog = fopen(TEMPORARY_LOG_FILE, "r"); 251 if (tmplog == NULL) { 252 LOGE("Can't open %s\n", TEMPORARY_LOG_FILE); 253 } else { 254 if (append) { 255 fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write 256 } 257 char buf[4096]; 258 while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log); 259 if (append) { 260 tmplog_offset = ftell(tmplog); 261 } 262 check_and_fclose(tmplog, TEMPORARY_LOG_FILE); 263 } 264 check_and_fclose(log, destination); 265 } 266 } 267 268 269 // clear the recovery command and prepare to boot a (hopefully working) system, 270 // copy our log file to cache as well (for the system to read), and 271 // record any intent we were asked to communicate back to the system. 272 // this function is idempotent: call it as many times as you like. 273 static void 274 finish_recovery(const char *send_intent) { 275 // By this point, we're ready to return to the main system... 276 if (send_intent != NULL) { 277 FILE *fp = fopen_path(INTENT_FILE, "w"); 278 if (fp == NULL) { 279 LOGE("Can't open %s\n", INTENT_FILE); 280 } else { 281 fputs(send_intent, fp); 282 check_and_fclose(fp, INTENT_FILE); 283 } 284 } 285 286 // Copy logs to cache so the system can find out what happened. 287 copy_log_file(LOG_FILE, true); 288 copy_log_file(LAST_LOG_FILE, false); 289 chmod(LAST_LOG_FILE, 0640); 290 291 // Reset to mormal system boot so recovery won't cycle indefinitely. 292 struct bootloader_message boot; 293 memset(&boot, 0, sizeof(boot)); 294 set_bootloader_message(&boot); 295 296 // Remove the command file, so recovery won't repeat indefinitely. 297 if (ensure_path_mounted(COMMAND_FILE) != 0 || 298 (unlink(COMMAND_FILE) && errno != ENOENT)) { 299 LOGW("Can't unlink %s\n", COMMAND_FILE); 300 } 301 302 sync(); // For good measure. 303 } 304 305 static int 306 erase_volume(const char *volume) { 307 ui_set_background(BACKGROUND_ICON_INSTALLING); 308 ui_show_indeterminate_progress(); 309 ui_print("Formatting %s...\n", volume); 310 311 if (strcmp(volume, "/cache") == 0) { 312 // Any part of the log we'd copied to cache is now gone. 313 // Reset the pointer so we copy from the beginning of the temp 314 // log. 315 tmplog_offset = 0; 316 } 317 318 return format_volume(volume); 319 } 320 321 static char* 322 copy_sideloaded_package(const char* original_path) { 323 if (ensure_path_mounted(original_path) != 0) { 324 LOGE("Can't mount %s\n", original_path); 325 return NULL; 326 } 327 328 if (ensure_path_mounted(SIDELOAD_TEMP_DIR) != 0) { 329 LOGE("Can't mount %s\n", SIDELOAD_TEMP_DIR); 330 return NULL; 331 } 332 333 if (mkdir(SIDELOAD_TEMP_DIR, 0700) != 0) { 334 if (errno != EEXIST) { 335 LOGE("Can't mkdir %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno)); 336 return NULL; 337 } 338 } 339 340 // verify that SIDELOAD_TEMP_DIR is exactly what we expect: a 341 // directory, owned by root, readable and writable only by root. 342 struct stat st; 343 if (stat(SIDELOAD_TEMP_DIR, &st) != 0) { 344 LOGE("failed to stat %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno)); 345 return NULL; 346 } 347 if (!S_ISDIR(st.st_mode)) { 348 LOGE("%s isn't a directory\n", SIDELOAD_TEMP_DIR); 349 return NULL; 350 } 351 if ((st.st_mode & 0777) != 0700) { 352 LOGE("%s has perms %o\n", SIDELOAD_TEMP_DIR, st.st_mode); 353 return NULL; 354 } 355 if (st.st_uid != 0) { 356 LOGE("%s owned by %lu; not root\n", SIDELOAD_TEMP_DIR, st.st_uid); 357 return NULL; 358 } 359 360 char copy_path[PATH_MAX]; 361 strcpy(copy_path, SIDELOAD_TEMP_DIR); 362 strcat(copy_path, "/package.zip"); 363 364 char* buffer = malloc(BUFSIZ); 365 if (buffer == NULL) { 366 LOGE("Failed to allocate buffer\n"); 367 return NULL; 368 } 369 370 size_t read; 371 FILE* fin = fopen(original_path, "rb"); 372 if (fin == NULL) { 373 LOGE("Failed to open %s (%s)\n", original_path, strerror(errno)); 374 return NULL; 375 } 376 FILE* fout = fopen(copy_path, "wb"); 377 if (fout == NULL) { 378 LOGE("Failed to open %s (%s)\n", copy_path, strerror(errno)); 379 return NULL; 380 } 381 382 while ((read = fread(buffer, 1, BUFSIZ, fin)) > 0) { 383 if (fwrite(buffer, 1, read, fout) != read) { 384 LOGE("Short write of %s (%s)\n", copy_path, strerror(errno)); 385 return NULL; 386 } 387 } 388 389 free(buffer); 390 391 if (fclose(fout) != 0) { 392 LOGE("Failed to close %s (%s)\n", copy_path, strerror(errno)); 393 return NULL; 394 } 395 396 if (fclose(fin) != 0) { 397 LOGE("Failed to close %s (%s)\n", original_path, strerror(errno)); 398 return NULL; 399 } 400 401 // "adb push" is happy to overwrite read-only files when it's 402 // running as root, but we'll try anyway. 403 if (chmod(copy_path, 0400) != 0) { 404 LOGE("Failed to chmod %s (%s)\n", copy_path, strerror(errno)); 405 return NULL; 406 } 407 408 return strdup(copy_path); 409 } 410 411 static char** 412 prepend_title(const char** headers) { 413 char* title[] = { "Android system recovery <" 414 EXPAND(RECOVERY_API_VERSION) "e>", 415 "", 416 NULL }; 417 418 // count the number of lines in our title, plus the 419 // caller-provided headers. 420 int count = 0; 421 char** p; 422 for (p = title; *p; ++p, ++count); 423 for (p = headers; *p; ++p, ++count); 424 425 char** new_headers = malloc((count+1) * sizeof(char*)); 426 char** h = new_headers; 427 for (p = title; *p; ++p, ++h) *h = *p; 428 for (p = headers; *p; ++p, ++h) *h = *p; 429 *h = NULL; 430 431 return new_headers; 432 } 433 434 static int 435 get_menu_selection(char** headers, char** items, int menu_only, 436 int initial_selection) { 437 // throw away keys pressed previously, so user doesn't 438 // accidentally trigger menu items. 439 ui_clear_key_queue(); 440 441 ui_start_menu(headers, items, initial_selection); 442 int selected = initial_selection; 443 int chosen_item = -1; 444 445 while (chosen_item < 0) { 446 int key = ui_wait_key(); 447 int visible = ui_text_visible(); 448 449 int action = device_handle_key(key, visible); 450 451 if (action < 0) { 452 switch (action) { 453 case HIGHLIGHT_UP: 454 --selected; 455 selected = ui_menu_select(selected); 456 break; 457 case HIGHLIGHT_DOWN: 458 ++selected; 459 selected = ui_menu_select(selected); 460 break; 461 case SELECT_ITEM: 462 chosen_item = selected; 463 break; 464 case NO_ACTION: 465 break; 466 } 467 } else if (!menu_only) { 468 chosen_item = action; 469 } 470 } 471 472 ui_end_menu(); 473 return chosen_item; 474 } 475 476 static int compare_string(const void* a, const void* b) { 477 return strcmp(*(const char**)a, *(const char**)b); 478 } 479 480 static int 481 sdcard_directory(const char* path) { 482 ensure_path_mounted(SDCARD_ROOT); 483 484 const char* MENU_HEADERS[] = { "Choose a package to install:", 485 path, 486 "", 487 NULL }; 488 DIR* d; 489 struct dirent* de; 490 d = opendir(path); 491 if (d == NULL) { 492 LOGE("error opening %s: %s\n", path, strerror(errno)); 493 ensure_path_unmounted(SDCARD_ROOT); 494 return 0; 495 } 496 497 char** headers = prepend_title(MENU_HEADERS); 498 499 int d_size = 0; 500 int d_alloc = 10; 501 char** dirs = malloc(d_alloc * sizeof(char*)); 502 int z_size = 1; 503 int z_alloc = 10; 504 char** zips = malloc(z_alloc * sizeof(char*)); 505 zips[0] = strdup("../"); 506 507 while ((de = readdir(d)) != NULL) { 508 int name_len = strlen(de->d_name); 509 510 if (de->d_type == DT_DIR) { 511 // skip "." and ".." entries 512 if (name_len == 1 && de->d_name[0] == '.') continue; 513 if (name_len == 2 && de->d_name[0] == '.' && 514 de->d_name[1] == '.') continue; 515 516 if (d_size >= d_alloc) { 517 d_alloc *= 2; 518 dirs = realloc(dirs, d_alloc * sizeof(char*)); 519 } 520 dirs[d_size] = malloc(name_len + 2); 521 strcpy(dirs[d_size], de->d_name); 522 dirs[d_size][name_len] = '/'; 523 dirs[d_size][name_len+1] = '\0'; 524 ++d_size; 525 } else if (de->d_type == DT_REG && 526 name_len >= 4 && 527 strncasecmp(de->d_name + (name_len-4), ".zip", 4) == 0) { 528 if (z_size >= z_alloc) { 529 z_alloc *= 2; 530 zips = realloc(zips, z_alloc * sizeof(char*)); 531 } 532 zips[z_size++] = strdup(de->d_name); 533 } 534 } 535 closedir(d); 536 537 qsort(dirs, d_size, sizeof(char*), compare_string); 538 qsort(zips, z_size, sizeof(char*), compare_string); 539 540 // append dirs to the zips list 541 if (d_size + z_size + 1 > z_alloc) { 542 z_alloc = d_size + z_size + 1; 543 zips = realloc(zips, z_alloc * sizeof(char*)); 544 } 545 memcpy(zips + z_size, dirs, d_size * sizeof(char*)); 546 free(dirs); 547 z_size += d_size; 548 zips[z_size] = NULL; 549 550 int result; 551 int chosen_item = 0; 552 do { 553 chosen_item = get_menu_selection(headers, zips, 1, chosen_item); 554 555 char* item = zips[chosen_item]; 556 int item_len = strlen(item); 557 if (chosen_item == 0) { // item 0 is always "../" 558 // go up but continue browsing (if the caller is sdcard_directory) 559 result = -1; 560 break; 561 } else if (item[item_len-1] == '/') { 562 // recurse down into a subdirectory 563 char new_path[PATH_MAX]; 564 strlcpy(new_path, path, PATH_MAX); 565 strlcat(new_path, "/", PATH_MAX); 566 strlcat(new_path, item, PATH_MAX); 567 new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/' 568 result = sdcard_directory(new_path); 569 if (result >= 0) break; 570 } else { 571 // selected a zip file: attempt to install it, and return 572 // the status to the caller. 573 char new_path[PATH_MAX]; 574 strlcpy(new_path, path, PATH_MAX); 575 strlcat(new_path, "/", PATH_MAX); 576 strlcat(new_path, item, PATH_MAX); 577 578 ui_print("\n-- Install %s ...\n", path); 579 set_sdcard_update_bootloader_message(); 580 char* copy = copy_sideloaded_package(new_path); 581 ensure_path_unmounted(SDCARD_ROOT); 582 if (copy) { 583 result = install_package(copy); 584 free(copy); 585 } else { 586 result = INSTALL_ERROR; 587 } 588 break; 589 } 590 } while (true); 591 592 int i; 593 for (i = 0; i < z_size; ++i) free(zips[i]); 594 free(zips); 595 free(headers); 596 597 ensure_path_unmounted(SDCARD_ROOT); 598 return result; 599 } 600 601 static void 602 wipe_data(int confirm) { 603 if (confirm) { 604 static char** title_headers = NULL; 605 606 if (title_headers == NULL) { 607 char* headers[] = { "Confirm wipe of all user data?", 608 " THIS CAN NOT BE UNDONE.", 609 "", 610 NULL }; 611 title_headers = prepend_title((const char**)headers); 612 } 613 614 char* items[] = { " No", 615 " No", 616 " No", 617 " No", 618 " No", 619 " No", 620 " No", 621 " Yes -- delete all user data", // [7] 622 " No", 623 " No", 624 " No", 625 NULL }; 626 627 int chosen_item = get_menu_selection(title_headers, items, 1, 0); 628 if (chosen_item != 7) { 629 return; 630 } 631 } 632 633 ui_print("\n-- Wiping data...\n"); 634 device_wipe_data(); 635 erase_volume("/data"); 636 erase_volume("/cache"); 637 ui_print("Data wipe complete.\n"); 638 } 639 640 static void 641 prompt_and_wait() { 642 char** headers = prepend_title((const char**)MENU_HEADERS); 643 644 for (;;) { 645 finish_recovery(NULL); 646 ui_reset_progress(); 647 648 int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0, 0); 649 650 // device-specific code may take some action here. It may 651 // return one of the core actions handled in the switch 652 // statement below. 653 chosen_item = device_perform_action(chosen_item); 654 655 switch (chosen_item) { 656 case ITEM_REBOOT: 657 return; 658 659 case ITEM_WIPE_DATA: 660 wipe_data(ui_text_visible()); 661 if (!ui_text_visible()) return; 662 break; 663 664 case ITEM_WIPE_CACHE: 665 ui_print("\n-- Wiping cache...\n"); 666 erase_volume("/cache"); 667 ui_print("Cache wipe complete.\n"); 668 if (!ui_text_visible()) return; 669 break; 670 671 case ITEM_APPLY_SDCARD: 672 ; 673 int status = sdcard_directory(SDCARD_ROOT); 674 if (status >= 0) { 675 if (status != INSTALL_SUCCESS) { 676 ui_set_background(BACKGROUND_ICON_ERROR); 677 ui_print("Installation aborted.\n"); 678 } else if (!ui_text_visible()) { 679 return; // reboot if logs aren't visible 680 } else { 681 ui_print("\nInstall from sdcard complete.\n"); 682 } 683 } 684 break; 685 } 686 } 687 } 688 689 static void 690 print_property(const char *key, const char *name, void *cookie) { 691 printf("%s=%s\n", key, name); 692 } 693 694 int 695 main(int argc, char **argv) { 696 time_t start = time(NULL); 697 698 // If these fail, there's not really anywhere to complain... 699 freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL); 700 freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL); 701 printf("Starting recovery on %s", ctime(&start)); 702 703 ui_init(); 704 ui_set_background(BACKGROUND_ICON_INSTALLING); 705 load_volume_table(); 706 get_args(&argc, &argv); 707 708 int previous_runs = 0; 709 const char *send_intent = NULL; 710 const char *update_package = NULL; 711 const char *encrypted_fs_mode = NULL; 712 int wipe_data = 0, wipe_cache = 0; 713 int toggle_secure_fs = 0; 714 encrypted_fs_info encrypted_fs_data; 715 716 int arg; 717 while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { 718 switch (arg) { 719 case 'p': previous_runs = atoi(optarg); break; 720 case 's': send_intent = optarg; break; 721 case 'u': update_package = optarg; break; 722 case 'w': wipe_data = wipe_cache = 1; break; 723 case 'c': wipe_cache = 1; break; 724 case 'e': encrypted_fs_mode = optarg; toggle_secure_fs = 1; break; 725 case 't': ui_show_text(1); break; 726 case '?': 727 LOGE("Invalid command argument\n"); 728 continue; 729 } 730 } 731 732 device_recovery_start(); 733 734 printf("Command:"); 735 for (arg = 0; arg < argc; arg++) { 736 printf(" \"%s\"", argv[arg]); 737 } 738 printf("\n"); 739 740 if (update_package) { 741 // For backwards compatibility on the cache partition only, if 742 // we're given an old 'root' path "CACHE:foo", change it to 743 // "/cache/foo". 744 if (strncmp(update_package, "CACHE:", 6) == 0) { 745 int len = strlen(update_package) + 10; 746 char* modified_path = malloc(len); 747 strlcpy(modified_path, "/cache/", len); 748 strlcat(modified_path, update_package+6, len); 749 printf("(replacing path \"%s\" with \"%s\")\n", 750 update_package, modified_path); 751 update_package = modified_path; 752 } 753 } 754 printf("\n"); 755 756 property_list(print_property, NULL); 757 printf("\n"); 758 759 int status = INSTALL_SUCCESS; 760 761 if (toggle_secure_fs) { 762 if (strcmp(encrypted_fs_mode,"on") == 0) { 763 encrypted_fs_data.mode = MODE_ENCRYPTED_FS_ENABLED; 764 ui_print("Enabling Encrypted FS.\n"); 765 } else if (strcmp(encrypted_fs_mode,"off") == 0) { 766 encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED; 767 ui_print("Disabling Encrypted FS.\n"); 768 } else { 769 ui_print("Error: invalid Encrypted FS setting.\n"); 770 status = INSTALL_ERROR; 771 } 772 773 // Recovery strategy: if the data partition is damaged, disable encrypted file systems. 774 // This preventsthe device recycling endlessly in recovery mode. 775 if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) && 776 (read_encrypted_fs_info(&encrypted_fs_data))) { 777 ui_print("Encrypted FS change aborted, resetting to disabled state.\n"); 778 encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED; 779 } 780 781 if (status != INSTALL_ERROR) { 782 if (erase_volume("/data")) { 783 ui_print("Data wipe failed.\n"); 784 status = INSTALL_ERROR; 785 } else if (erase_volume("/cache")) { 786 ui_print("Cache wipe failed.\n"); 787 status = INSTALL_ERROR; 788 } else if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) && 789 (restore_encrypted_fs_info(&encrypted_fs_data))) { 790 ui_print("Encrypted FS change aborted.\n"); 791 status = INSTALL_ERROR; 792 } else { 793 ui_print("Successfully updated Encrypted FS.\n"); 794 status = INSTALL_SUCCESS; 795 } 796 } 797 } else if (update_package != NULL) { 798 status = install_package(update_package); 799 if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); 800 } else if (wipe_data) { 801 if (device_wipe_data()) status = INSTALL_ERROR; 802 if (erase_volume("/data")) status = INSTALL_ERROR; 803 if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; 804 if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n"); 805 } else if (wipe_cache) { 806 if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; 807 if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n"); 808 } else { 809 status = INSTALL_ERROR; // No command specified 810 } 811 812 if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR); 813 if (status != INSTALL_SUCCESS || ui_text_visible()) { 814 prompt_and_wait(); 815 } 816 817 // Otherwise, get ready to boot the main system... 818 finish_recovery(send_intent); 819 ui_print("Rebooting...\n"); 820 sync(); 821 reboot(RB_AUTOBOOT); 822 return EXIT_SUCCESS; 823 } 824