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