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