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