• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*
fopen_path(const char * path,const char * mode)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
check_and_fclose(FILE * fp,const char * name)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
get_args(int * argc,char *** argv)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
set_sdcard_update_bootloader_message()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
copy_log_file(const char * source,const char * destination,int append)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
rotate_last_logs(int max)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
copy_logs()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
finish_recovery(const char * send_intent)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
erase_volume(const char * volume)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*
copy_sideloaded_package(const char * original_path)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**
prepend_title(const char * const * headers)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
get_menu_selection(const char * const * headers,const char * const * items,int menu_only,int initial_selection,Device * device)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 
compare_string(const void * a,const void * b)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
update_directory(const char * path,const char * unmount_when_done,int * wipe_cache,Device * device)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
wipe_data(int confirm,Device * device)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
prompt_and_wait(Device * device,int status)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
print_property(const char * key,const char * name,void * cookie)880 print_property(const char *key, const char *name, void *cookie) {
881     printf("%s=%s\n", key, name);
882 }
883 
884 static void
load_locale_from_cache()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
ui_print(const char * format,...)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
main(int argc,char ** argv)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