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