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