blob: 64091305a3b19fb23a3c7eea72e208c167d41c7c [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
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>
Doug Zongker7c3ae452013-05-14 11:03:02 -070018#include <dirent.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080019#include <errno.h>
20#include <fcntl.h>
21#include <getopt.h>
22#include <limits.h>
23#include <linux/input.h>
Doug Zongker7c3ae452013-05-14 11:03:02 -070024#include <stdarg.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080025#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Doug Zongker23ceeea2010-07-08 17:27:55 -070028#include <sys/stat.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080029#include <sys/types.h>
30#include <time.h>
31#include <unistd.h>
32
33#include "bootloader.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080034#include "common.h"
35#include "cutils/properties.h"
Dees_Troy38bd7602012-09-14 13:33:53 -040036#ifdef ANDROID_RB_RESTART
Ken Sumrall6e4472a2011-03-07 23:37:27 -080037#include "cutils/android_reboot.h"
Dees_Troy38bd7602012-09-14 13:33:53 -040038#else
39#include <sys/reboot.h>
40#endif
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080041#include "install.h"
42#include "minui/minui.h"
43#include "minzip/DirUtil.h"
44#include "roots.h"
Doug Zongker28ce47c2011-10-28 10:33:05 -070045#include "ui.h"
Doug Zongker211aebc2011-10-28 15:13:10 -070046#include "screen_ui.h"
Doug Zongkerdaefc1d2011-10-31 09:34:15 -070047#include "device.h"
Doug Zongker9270a202012-01-09 15:16:13 -080048#include "adb_install.h"
49extern "C" {
50#include "minadbd/adb.h"
51}
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080052
Dees_Troy7d15c252012-09-05 20:47:21 -040053extern "C" {
Dees_Troy7d15c252012-09-05 20:47:21 -040054#include "data.h"
55#include "gui/gui.h"
56}
57#include "partitions.hpp"
Dees_Troy51127312012-09-08 13:08:49 -040058#include "variables.h"
Dees_Troy812660f2012-09-20 09:55:17 -040059#include "openrecoveryscript.hpp"
Dees_Troya58bead2012-09-27 09:49:29 -040060#include "twrp-functions.hpp"
Dees_Troy7d15c252012-09-05 20:47:21 -040061
Dees_Troy5bf43922012-09-07 16:07:55 -040062TWPartitionManager PartitionManager;
Dees_Troy7d15c252012-09-05 20:47:21 -040063
Stephen Smalley779701d2012-02-09 14:13:23 -050064struct selabel_handle *sehandle;
65
bigbiff bigbiffe60683a2013-02-22 20:55:50 -050066
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080067static const struct option OPTIONS[] = {
68 { "send_intent", required_argument, NULL, 's' },
69 { "update_package", required_argument, NULL, 'u' },
70 { "wipe_data", no_argument, NULL, 'w' },
71 { "wipe_cache", no_argument, NULL, 'c' },
Doug Zongker4bc98062010-09-03 11:00:13 -070072 { "show_text", no_argument, NULL, 't' },
Doug Zongkere5d5ac72012-04-12 11:01:22 -070073 { "just_exit", no_argument, NULL, 'x' },
Doug Zongker02ec6b82012-08-22 17:26:40 -070074 { "locale", required_argument, NULL, 'l' },
Doug Zongker988500b2009-10-06 14:41:38 -070075 { NULL, 0, NULL, 0 },
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080076};
77
Doug Zongkerda1ebae2013-05-16 11:23:48 -070078#define LAST_LOG_FILE "/cache/recovery/last_log"
79
Doug Zongker6d0d7ac2013-07-09 13:34:55 -070080static const char *CACHE_LOG_DIR = "/cache/recovery";
Doug Zongkerd4208f92010-09-20 12:16:13 -070081static const char *COMMAND_FILE = "/cache/recovery/command";
82static const char *INTENT_FILE = "/cache/recovery/intent";
83static const char *LOG_FILE = "/cache/recovery/log";
Doug Zongkerd0181b82011-10-19 10:51:12 -070084static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
Doug Zongker8b240cc2012-08-29 15:19:29 -070085static const char *LOCALE_FILE = "/cache/recovery/last_locale";
Michael Ward9d2629c2011-06-23 22:14:24 -070086static const char *CACHE_ROOT = "/cache";
Doug Zongkerd4208f92010-09-20 12:16:13 -070087static const char *SDCARD_ROOT = "/sdcard";
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080088static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
Doug Zongkerd0181b82011-10-19 10:51:12 -070089static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
Doug Zongkerd4208f92010-09-20 12:16:13 -070090static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080091
Doug Zongker211aebc2011-10-28 15:13:10 -070092RecoveryUI* ui = NULL;
Doug Zongker02ec6b82012-08-22 17:26:40 -070093char* locale = NULL;
Doug Zongkerc0441d12013-07-31 11:28:24 -070094char recovery_version[PROPERTY_VALUE_MAX+1];
Doug Zongker211aebc2011-10-28 15:13:10 -070095
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080096/*
97 * The recovery tool communicates with the main system through /cache files.
98 * /cache/recovery/command - INPUT - command line for tool, one arg per line
99 * /cache/recovery/log - OUTPUT - combined log file from recovery run(s)
100 * /cache/recovery/intent - OUTPUT - intent that was passed in
101 *
102 * The arguments which may be supplied in the recovery.command file:
103 * --send_intent=anystring - write the text out to recovery.intent
Doug Zongkerd4208f92010-09-20 12:16:13 -0700104 * --update_package=path - verify install an OTA package file
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800105 * --wipe_data - erase user data (and cache), then reboot
106 * --wipe_cache - wipe cache (but not user data), then reboot
Oscar Montemayor05231562009-11-30 08:40:57 -0800107 * --set_encrypted_filesystem=on|off - enables / diasables encrypted fs
Doug Zongkere5d5ac72012-04-12 11:01:22 -0700108 * --just_exit - do nothing; exit and reboot
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800109 *
110 * After completing, we remove /cache/recovery/command and reboot.
111 * Arguments may also be supplied in the bootloader control block (BCB).
112 * These important scenarios must be safely restartable at any point:
113 *
114 * FACTORY RESET
115 * 1. user selects "factory reset"
116 * 2. main system writes "--wipe_data" to /cache/recovery/command
117 * 3. main system reboots into recovery
118 * 4. get_args() writes BCB with "boot-recovery" and "--wipe_data"
119 * -- after this, rebooting will restart the erase --
Doug Zongkerd4208f92010-09-20 12:16:13 -0700120 * 5. erase_volume() reformats /data
121 * 6. erase_volume() reformats /cache
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800122 * 7. finish_recovery() erases BCB
123 * -- after this, rebooting will restart the main system --
124 * 8. main() calls reboot() to boot main system
125 *
126 * OTA INSTALL
127 * 1. main system downloads OTA package to /cache/some-filename.zip
Doug Zongker9b125b02010-09-22 12:01:37 -0700128 * 2. main system writes "--update_package=/cache/some-filename.zip"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800129 * 3. main system reboots into recovery
130 * 4. get_args() writes BCB with "boot-recovery" and "--update_package=..."
131 * -- after this, rebooting will attempt to reinstall the update --
132 * 5. install_package() attempts to install the update
133 * NOTE: the package install must itself be restartable from any point
134 * 6. finish_recovery() erases BCB
135 * -- after this, rebooting will (try to) restart the main system --
136 * 7. ** if install failed **
137 * 7a. prompt_and_wait() shows an error icon and waits for the user
138 * 7b; the user reboots (pulling the battery, etc) into the main system
139 * 8. main() calls maybe_install_firmware_update()
140 * ** if the update contained radio/hboot firmware **:
141 * 8a. m_i_f_u() writes BCB with "boot-recovery" and "--wipe_cache"
142 * -- after this, rebooting will reformat cache & restart main system --
143 * 8b. m_i_f_u() writes firmware image into raw cache partition
144 * 8c. m_i_f_u() writes BCB with "update-radio/hboot" and "--wipe_cache"
145 * -- after this, rebooting will attempt to reinstall firmware --
146 * 8d. bootloader tries to flash firmware
147 * 8e. bootloader writes BCB with "boot-recovery" (keeping "--wipe_cache")
148 * -- after this, rebooting will reformat cache & restart main system --
Doug Zongkerd4208f92010-09-20 12:16:13 -0700149 * 8f. erase_volume() reformats /cache
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800150 * 8g. finish_recovery() erases BCB
151 * -- after this, rebooting will (try to) restart the main system --
152 * 9. main() calls reboot() to boot main system
153 */
154
155static const int MAX_ARG_LENGTH = 4096;
156static const int MAX_ARGS = 100;
157
Doug Zongkerd4208f92010-09-20 12:16:13 -0700158// open a given path, mounting partitions as necessary
Doug Zongker469243e2011-04-12 09:28:10 -0700159FILE*
Doug Zongkerd4208f92010-09-20 12:16:13 -0700160fopen_path(const char *path, const char *mode) {
161 if (ensure_path_mounted(path) != 0) {
162 LOGE("Can't mount %s\n", path);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800163 return NULL;
164 }
165
166 // When writing, try to create the containing directory, if necessary.
167 // Use generous permissions, the system (init.rc) will reset them.
Stephen Smalley779701d2012-02-09 14:13:23 -0500168 if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1, sehandle);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800169
170 FILE *fp = fopen(path, mode);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800171 return fp;
172}
173
174// close a file, log an error if the error indicator is set
175static void
176check_and_fclose(FILE *fp, const char *name) {
177 fflush(fp);
178 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
179 fclose(fp);
180}
181
182// command line args come from, in decreasing precedence:
183// - the actual command line
184// - the bootloader control block (one per line, after "recovery")
185// - the contents of COMMAND_FILE (one per line)
186static void
187get_args(int *argc, char ***argv) {
188 struct bootloader_message boot;
189 memset(&boot, 0, sizeof(boot));
190 get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
191
192 if (boot.command[0] != 0 && boot.command[0] != 255) {
193 LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
194 }
195
196 if (boot.status[0] != 0 && boot.status[0] != 255) {
197 LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status);
198 }
199
200 // --- if arguments weren't supplied, look in the bootloader control block
201 if (*argc <= 1) {
202 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
203 const char *arg = strtok(boot.recovery, "\n");
204 if (arg != NULL && !strcmp(arg, "recovery")) {
205 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
206 (*argv)[0] = strdup(arg);
207 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
208 if ((arg = strtok(NULL, "\n")) == NULL) break;
209 (*argv)[*argc] = strdup(arg);
210 }
211 LOGI("Got arguments from boot message\n");
212 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
213 LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
214 }
215 }
216
217 // --- if that doesn't work, try the command file
218 if (*argc <= 1) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700219 FILE *fp = fopen_path(COMMAND_FILE, "r");
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800220 if (fp != NULL) {
Jin Feng93ffa752013-06-04 17:46:24 +0800221 char *token;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800222 char *argv0 = (*argv)[0];
223 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
224 (*argv)[0] = argv0; // use the same program name
225
226 char buf[MAX_ARG_LENGTH];
227 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
228 if (!fgets(buf, sizeof(buf), fp)) break;
Jin Feng93ffa752013-06-04 17:46:24 +0800229 token = strtok(buf, "\r\n");
230 if (token != NULL) {
231 (*argv)[*argc] = strdup(token); // Strip newline.
232 } else {
233 --*argc;
234 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800235 }
236
237 check_and_fclose(fp, COMMAND_FILE);
238 LOGI("Got arguments from %s\n", COMMAND_FILE);
239 }
240 }
241
242 // --> write the arguments we have back into the bootloader control block
243 // always boot into recovery after this (until finish_recovery() is called)
244 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
245 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
246 int i;
247 for (i = 1; i < *argc; ++i) {
248 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
249 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
250 }
251 set_bootloader_message(&boot);
252}
253
Doug Zongker34c98df2009-08-18 12:05:45 -0700254static void
Oscar Montemayor05231562009-11-30 08:40:57 -0800255set_sdcard_update_bootloader_message() {
Doug Zongker34c98df2009-08-18 12:05:45 -0700256 struct bootloader_message boot;
257 memset(&boot, 0, sizeof(boot));
258 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
259 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
260 set_bootloader_message(&boot);
261}
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800262
Doug Zongker2c3539e2010-09-29 13:21:30 -0700263// How much of the temp log we have copied to the copy in cache.
Dees_Troy7d15c252012-09-05 20:47:21 -0400264//static long tmplog_offset = 0;
Doug Zongker2c3539e2010-09-29 13:21:30 -0700265
266static void
Doug Zongkerd0181b82011-10-19 10:51:12 -0700267copy_log_file(const char* source, const char* destination, int append) {
Doug Zongker2c3539e2010-09-29 13:21:30 -0700268 FILE *log = fopen_path(destination, append ? "a" : "w");
269 if (log == NULL) {
270 LOGE("Can't open %s\n", destination);
271 } else {
Doug Zongkerd0181b82011-10-19 10:51:12 -0700272 FILE *tmplog = fopen(source, "r");
273 if (tmplog != NULL) {
Doug Zongker2c3539e2010-09-29 13:21:30 -0700274 if (append) {
275 fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write
276 }
277 char buf[4096];
278 while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log);
279 if (append) {
280 tmplog_offset = ftell(tmplog);
281 }
Doug Zongkerd0181b82011-10-19 10:51:12 -0700282 check_and_fclose(tmplog, source);
Doug Zongker2c3539e2010-09-29 13:21:30 -0700283 }
284 check_and_fclose(log, destination);
285 }
286}
287
Doug Zongkerda1ebae2013-05-16 11:23:48 -0700288// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max
289// Overwrites any existing last_log.$max.
290static void
291rotate_last_logs(int max) {
292 char oldfn[256];
293 char newfn[256];
294
295 int i;
296 for (i = max-1; i >= 0; --i) {
297 snprintf(oldfn, sizeof(oldfn), (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i);
298 snprintf(newfn, sizeof(newfn), LAST_LOG_FILE ".%d", i+1);
299 // ignore errors
300 rename(oldfn, newfn);
301 }
302}
Doug Zongker2c3539e2010-09-29 13:21:30 -0700303
Doug Zongkerf24fd7e2013-07-02 11:43:25 -0700304static void
305copy_logs() {
306 // Copy logs to cache so the system can find out what happened.
307 copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
308 copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
309 copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
310 chmod(LOG_FILE, 0600);
311 chown(LOG_FILE, 1000, 1000); // system user
312 chmod(LAST_LOG_FILE, 0640);
313 chmod(LAST_INSTALL_FILE, 0644);
314 sync();
315}
316
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800317// clear the recovery command and prepare to boot a (hopefully working) system,
318// copy our log file to cache as well (for the system to read), and
319// record any intent we were asked to communicate back to the system.
320// this function is idempotent: call it as many times as you like.
321static void
Oscar Montemayor05231562009-11-30 08:40:57 -0800322finish_recovery(const char *send_intent) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800323 // By this point, we're ready to return to the main system...
324 if (send_intent != NULL) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700325 FILE *fp = fopen_path(INTENT_FILE, "w");
Jay Freeman (saurik)619ec2f2008-11-17 01:56:05 +0000326 if (fp == NULL) {
327 LOGE("Can't open %s\n", INTENT_FILE);
328 } else {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800329 fputs(send_intent, fp);
330 check_and_fclose(fp, INTENT_FILE);
331 }
332 }
333
Doug Zongker4f33e552012-08-23 13:16:12 -0700334 // Save the locale to cache, so if recovery is next started up
335 // without a --locale argument (eg, directly from the bootloader)
336 // it will use the last-known locale.
337 if (locale != NULL) {
338 LOGI("Saving locale \"%s\"\n", locale);
339 FILE* fp = fopen_path(LOCALE_FILE, "w");
340 fwrite(locale, 1, strlen(locale), fp);
341 fflush(fp);
342 fsync(fileno(fp));
343 check_and_fclose(fp, LOCALE_FILE);
344 }
345
Doug Zongkerf24fd7e2013-07-02 11:43:25 -0700346 copy_logs();
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800347
Doug Zongkere5d5ac72012-04-12 11:01:22 -0700348 // Reset to normal system boot so recovery won't cycle indefinitely.
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800349 struct bootloader_message boot;
350 memset(&boot, 0, sizeof(boot));
351 set_bootloader_message(&boot);
352
353 // Remove the command file, so recovery won't repeat indefinitely.
Doug Zongkerd4208f92010-09-20 12:16:13 -0700354 if (ensure_path_mounted(COMMAND_FILE) != 0 ||
355 (unlink(COMMAND_FILE) && errno != ENOENT)) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800356 LOGW("Can't unlink %s\n", COMMAND_FILE);
357 }
358
Doug Zongkerd0181b82011-10-19 10:51:12 -0700359 ensure_path_unmounted(CACHE_ROOT);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800360 sync(); // For good measure.
361}
362
Doug Zongker6d0d7ac2013-07-09 13:34:55 -0700363typedef struct _saved_log_file {
364 char* name;
365 struct stat st;
366 unsigned char* data;
367 struct _saved_log_file* next;
368} saved_log_file;
369
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800370static int
Doug Zongkerd4208f92010-09-20 12:16:13 -0700371erase_volume(const char *volume) {
Doug Zongker6d0d7ac2013-07-09 13:34:55 -0700372 bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
373
Doug Zongker02ec6b82012-08-22 17:26:40 -0700374 ui->SetBackground(RecoveryUI::ERASING);
Doug Zongker211aebc2011-10-28 15:13:10 -0700375 ui->SetProgressType(RecoveryUI::INDETERMINATE);
Doug Zongker6d0d7ac2013-07-09 13:34:55 -0700376
377 saved_log_file* head = NULL;
378
379 if (is_cache) {
380 // If we're reformatting /cache, we load any
381 // "/cache/recovery/last*" files into memory, so we can restore
382 // them after the reformat.
383
384 ensure_path_mounted(volume);
385
386 DIR* d;
387 struct dirent* de;
388 d = opendir(CACHE_LOG_DIR);
389 if (d) {
390 char path[PATH_MAX];
391 strcpy(path, CACHE_LOG_DIR);
392 strcat(path, "/");
393 int path_len = strlen(path);
394 while ((de = readdir(d)) != NULL) {
395 if (strncmp(de->d_name, "last", 4) == 0) {
396 saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file));
397 strcpy(path+path_len, de->d_name);
398 p->name = strdup(path);
399 if (stat(path, &(p->st)) == 0) {
400 // truncate files to 512kb
401 if (p->st.st_size > (1 << 19)) {
402 p->st.st_size = 1 << 19;
403 }
404 p->data = (unsigned char*) malloc(p->st.st_size);
405 FILE* f = fopen(path, "rb");
406 fread(p->data, 1, p->st.st_size, f);
407 fclose(f);
408 p->next = head;
409 head = p;
410 } else {
411 free(p);
412 }
413 }
414 }
415 closedir(d);
416 } else {
417 if (errno != ENOENT) {
418 printf("opendir failed: %s\n", strerror(errno));
419 }
420 }
421 }
422
Doug Zongker211aebc2011-10-28 15:13:10 -0700423 ui->Print("Formatting %s...\n", volume);
Doug Zongker2c3539e2010-09-29 13:21:30 -0700424
Doug Zongkerd0181b82011-10-19 10:51:12 -0700425 ensure_path_unmounted(volume);
Doug Zongker6d0d7ac2013-07-09 13:34:55 -0700426 int result = format_volume(volume);
Doug Zongkerd0181b82011-10-19 10:51:12 -0700427
Doug Zongker6d0d7ac2013-07-09 13:34:55 -0700428 if (is_cache) {
429 while (head) {
430 FILE* f = fopen_path(head->name, "wb");
431 if (f) {
432 fwrite(head->data, 1, head->st.st_size, f);
433 fclose(f);
434 chmod(head->name, head->st.st_mode);
435 chown(head->name, head->st.st_uid, head->st.st_gid);
436 }
437 free(head->name);
438 free(head->data);
439 saved_log_file* temp = head->next;
440 free(head);
441 head = temp;
442 }
443
Doug Zongker2c3539e2010-09-29 13:21:30 -0700444 // Any part of the log we'd copied to cache is now gone.
445 // Reset the pointer so we copy from the beginning of the temp
446 // log.
447 tmplog_offset = 0;
Doug Zongker6d0d7ac2013-07-09 13:34:55 -0700448 copy_logs();
Doug Zongker2c3539e2010-09-29 13:21:30 -0700449 }
450
Doug Zongker6d0d7ac2013-07-09 13:34:55 -0700451 return result;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800452}
453
Doug Zongker23ceeea2010-07-08 17:27:55 -0700454static char*
Doug Zongkerd4208f92010-09-20 12:16:13 -0700455copy_sideloaded_package(const char* original_path) {
456 if (ensure_path_mounted(original_path) != 0) {
457 LOGE("Can't mount %s\n", original_path);
Doug Zongker23ceeea2010-07-08 17:27:55 -0700458 return NULL;
459 }
460
Doug Zongkerd4208f92010-09-20 12:16:13 -0700461 if (ensure_path_mounted(SIDELOAD_TEMP_DIR) != 0) {
Doug Zongker23ceeea2010-07-08 17:27:55 -0700462 LOGE("Can't mount %s\n", SIDELOAD_TEMP_DIR);
463 return NULL;
464 }
465
Doug Zongkerd4208f92010-09-20 12:16:13 -0700466 if (mkdir(SIDELOAD_TEMP_DIR, 0700) != 0) {
Doug Zongker23ceeea2010-07-08 17:27:55 -0700467 if (errno != EEXIST) {
468 LOGE("Can't mkdir %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno));
469 return NULL;
470 }
471 }
472
Doug Zongkerd4208f92010-09-20 12:16:13 -0700473 // verify that SIDELOAD_TEMP_DIR is exactly what we expect: a
474 // directory, owned by root, readable and writable only by root.
Doug Zongker23ceeea2010-07-08 17:27:55 -0700475 struct stat st;
Doug Zongkerd4208f92010-09-20 12:16:13 -0700476 if (stat(SIDELOAD_TEMP_DIR, &st) != 0) {
477 LOGE("failed to stat %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno));
Doug Zongker23ceeea2010-07-08 17:27:55 -0700478 return NULL;
479 }
480 if (!S_ISDIR(st.st_mode)) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700481 LOGE("%s isn't a directory\n", SIDELOAD_TEMP_DIR);
Doug Zongker23ceeea2010-07-08 17:27:55 -0700482 return NULL;
483 }
484 if ((st.st_mode & 0777) != 0700) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700485 LOGE("%s has perms %o\n", SIDELOAD_TEMP_DIR, st.st_mode);
Doug Zongker23ceeea2010-07-08 17:27:55 -0700486 return NULL;
487 }
488 if (st.st_uid != 0) {
Doug Zongkerd4208f92010-09-20 12:16:13 -0700489 LOGE("%s owned by %lu; not root\n", SIDELOAD_TEMP_DIR, st.st_uid);
Doug Zongker23ceeea2010-07-08 17:27:55 -0700490 return NULL;
491 }
492
Doug Zongkerd4208f92010-09-20 12:16:13 -0700493 char copy_path[PATH_MAX];
494 strcpy(copy_path, SIDELOAD_TEMP_DIR);
Doug Zongker23ceeea2010-07-08 17:27:55 -0700495 strcat(copy_path, "/package.zip");
496
Doug Zongker28ce47c2011-10-28 10:33:05 -0700497 char* buffer = (char*)malloc(BUFSIZ);
Doug Zongker23ceeea2010-07-08 17:27:55 -0700498 if (buffer == NULL) {
499 LOGE("Failed to allocate buffer\n");
500 return NULL;
501 }
502
503 size_t read;
504 FILE* fin = fopen(original_path, "rb");
505 if (fin == NULL) {
506 LOGE("Failed to open %s (%s)\n", original_path, strerror(errno));
507 return NULL;
508 }
509 FILE* fout = fopen(copy_path, "wb");
510 if (fout == NULL) {
511 LOGE("Failed to open %s (%s)\n", copy_path, strerror(errno));
512 return NULL;
513 }
514
515 while ((read = fread(buffer, 1, BUFSIZ, fin)) > 0) {
516 if (fwrite(buffer, 1, read, fout) != read) {
517 LOGE("Short write of %s (%s)\n", copy_path, strerror(errno));
518 return NULL;
519 }
520 }
521
522 free(buffer);
523
524 if (fclose(fout) != 0) {
525 LOGE("Failed to close %s (%s)\n", copy_path, strerror(errno));
526 return NULL;
527 }
528
529 if (fclose(fin) != 0) {
530 LOGE("Failed to close %s (%s)\n", original_path, strerror(errno));
531 return NULL;
532 }
533
534 // "adb push" is happy to overwrite read-only files when it's
535 // running as root, but we'll try anyway.
536 if (chmod(copy_path, 0400) != 0) {
537 LOGE("Failed to chmod %s (%s)\n", copy_path, strerror(errno));
538 return NULL;
539 }
540
Doug Zongkerd4208f92010-09-20 12:16:13 -0700541 return strdup(copy_path);
Doug Zongker23ceeea2010-07-08 17:27:55 -0700542}
543
Doug Zongker28ce47c2011-10-28 10:33:05 -0700544static const char**
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700545prepend_title(const char* const* headers) {
Doug Zongkerd6837852009-06-17 22:07:13 -0700546 // count the number of lines in our title, plus the
Doug Zongkerf93d8162009-09-22 15:16:02 -0700547 // caller-provided headers.
Doug Zongkerc0441d12013-07-31 11:28:24 -0700548 int count = 3; // our title has 3 lines
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700549 const char* const* p;
Doug Zongkerf93d8162009-09-22 15:16:02 -0700550 for (p = headers; *p; ++p, ++count);
Doug Zongkerd6837852009-06-17 22:07:13 -0700551
Doug Zongker28ce47c2011-10-28 10:33:05 -0700552 const char** new_headers = (const char**)malloc((count+1) * sizeof(char*));
553 const char** h = new_headers;
Doug Zongkerc0441d12013-07-31 11:28:24 -0700554 *(h++) = "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>";
555 *(h++) = recovery_version;
556 *(h++) = "";
Doug Zongkerf93d8162009-09-22 15:16:02 -0700557 for (p = headers; *p; ++p, ++h) *h = *p;
Doug Zongkerd6837852009-06-17 22:07:13 -0700558 *h = NULL;
559
Doug Zongkerf93d8162009-09-22 15:16:02 -0700560 return new_headers;
561}
562
563static int
Doug Zongker28ce47c2011-10-28 10:33:05 -0700564get_menu_selection(const char* const * headers, const char* const * items,
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700565 int menu_only, int initial_selection, Device* device) {
Doug Zongkerf93d8162009-09-22 15:16:02 -0700566 // throw away keys pressed previously, so user doesn't
567 // accidentally trigger menu items.
Doug Zongker211aebc2011-10-28 15:13:10 -0700568 ui->FlushKeys();
Doug Zongkerf93d8162009-09-22 15:16:02 -0700569
Doug Zongker211aebc2011-10-28 15:13:10 -0700570 ui->StartMenu(headers, items, initial_selection);
Doug Zongker8674a722010-09-15 11:08:23 -0700571 int selected = initial_selection;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800572 int chosen_item = -1;
573
Doug Zongkerf93d8162009-09-22 15:16:02 -0700574 while (chosen_item < 0) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700575 int key = ui->WaitKey();
576 int visible = ui->IsTextVisible();
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800577
Doug Zongker5cae4452011-01-25 13:15:30 -0800578 if (key == -1) { // ui_wait_key() timed out
Doug Zongker211aebc2011-10-28 15:13:10 -0700579 if (ui->WasTextEverVisible()) {
Doug Zongker5cae4452011-01-25 13:15:30 -0800580 continue;
581 } else {
582 LOGI("timed out waiting for key input; rebooting.\n");
Doug Zongker211aebc2011-10-28 15:13:10 -0700583 ui->EndMenu();
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700584 return 0; // XXX fixme
Doug Zongker5cae4452011-01-25 13:15:30 -0800585 }
586 }
587
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700588 int action = device->HandleMenuKey(key, visible);
Doug Zongkerddd6a282009-06-09 12:22:33 -0700589
590 if (action < 0) {
591 switch (action) {
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700592 case Device::kHighlightUp:
Doug Zongkerddd6a282009-06-09 12:22:33 -0700593 --selected;
Doug Zongker211aebc2011-10-28 15:13:10 -0700594 selected = ui->SelectMenu(selected);
Doug Zongkerddd6a282009-06-09 12:22:33 -0700595 break;
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700596 case Device::kHighlightDown:
Doug Zongkerddd6a282009-06-09 12:22:33 -0700597 ++selected;
Doug Zongker211aebc2011-10-28 15:13:10 -0700598 selected = ui->SelectMenu(selected);
Doug Zongkerddd6a282009-06-09 12:22:33 -0700599 break;
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700600 case Device::kInvokeItem:
Doug Zongkerddd6a282009-06-09 12:22:33 -0700601 chosen_item = selected;
602 break;
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700603 case Device::kNoAction:
Doug Zongkerddd6a282009-06-09 12:22:33 -0700604 break;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800605 }
Doug Zongkerf93d8162009-09-22 15:16:02 -0700606 } else if (!menu_only) {
Doug Zongkerddd6a282009-06-09 12:22:33 -0700607 chosen_item = action;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800608 }
Doug Zongkerf93d8162009-09-22 15:16:02 -0700609 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800610
Doug Zongker211aebc2011-10-28 15:13:10 -0700611 ui->EndMenu();
Doug Zongkerf93d8162009-09-22 15:16:02 -0700612 return chosen_item;
613}
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800614
Doug Zongker8674a722010-09-15 11:08:23 -0700615static int compare_string(const void* a, const void* b) {
616 return strcmp(*(const char**)a, *(const char**)b);
617}
618
619static int
Doug Zongkerd0181b82011-10-19 10:51:12 -0700620update_directory(const char* path, const char* unmount_when_done,
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700621 int* wipe_cache, Device* device) {
Michael Ward9d2629c2011-06-23 22:14:24 -0700622 ensure_path_mounted(path);
Doug Zongkerc18eeb82010-09-21 16:49:26 -0700623
Doug Zongker8674a722010-09-15 11:08:23 -0700624 const char* MENU_HEADERS[] = { "Choose a package to install:",
Doug Zongkerd4208f92010-09-20 12:16:13 -0700625 path,
Doug Zongker8674a722010-09-15 11:08:23 -0700626 "",
627 NULL };
628 DIR* d;
629 struct dirent* de;
Doug Zongkerd4208f92010-09-20 12:16:13 -0700630 d = opendir(path);
Doug Zongker8674a722010-09-15 11:08:23 -0700631 if (d == NULL) {
632 LOGE("error opening %s: %s\n", path, strerror(errno));
Michael Ward9d2629c2011-06-23 22:14:24 -0700633 if (unmount_when_done != NULL) {
634 ensure_path_unmounted(unmount_when_done);
635 }
Doug Zongker8674a722010-09-15 11:08:23 -0700636 return 0;
637 }
638
Doug Zongker28ce47c2011-10-28 10:33:05 -0700639 const char** headers = prepend_title(MENU_HEADERS);
Doug Zongker8674a722010-09-15 11:08:23 -0700640
641 int d_size = 0;
642 int d_alloc = 10;
Doug Zongker28ce47c2011-10-28 10:33:05 -0700643 char** dirs = (char**)malloc(d_alloc * sizeof(char*));
Doug Zongker8674a722010-09-15 11:08:23 -0700644 int z_size = 1;
645 int z_alloc = 10;
Doug Zongker28ce47c2011-10-28 10:33:05 -0700646 char** zips = (char**)malloc(z_alloc * sizeof(char*));
Doug Zongker8674a722010-09-15 11:08:23 -0700647 zips[0] = strdup("../");
648
649 while ((de = readdir(d)) != NULL) {
650 int name_len = strlen(de->d_name);
651
652 if (de->d_type == DT_DIR) {
653 // skip "." and ".." entries
654 if (name_len == 1 && de->d_name[0] == '.') continue;
655 if (name_len == 2 && de->d_name[0] == '.' &&
656 de->d_name[1] == '.') continue;
657
658 if (d_size >= d_alloc) {
659 d_alloc *= 2;
Doug Zongker28ce47c2011-10-28 10:33:05 -0700660 dirs = (char**)realloc(dirs, d_alloc * sizeof(char*));
Doug Zongker8674a722010-09-15 11:08:23 -0700661 }
Doug Zongker28ce47c2011-10-28 10:33:05 -0700662 dirs[d_size] = (char*)malloc(name_len + 2);
Doug Zongker8674a722010-09-15 11:08:23 -0700663 strcpy(dirs[d_size], de->d_name);
664 dirs[d_size][name_len] = '/';
665 dirs[d_size][name_len+1] = '\0';
666 ++d_size;
667 } else if (de->d_type == DT_REG &&
668 name_len >= 4 &&
669 strncasecmp(de->d_name + (name_len-4), ".zip", 4) == 0) {
670 if (z_size >= z_alloc) {
671 z_alloc *= 2;
Doug Zongker28ce47c2011-10-28 10:33:05 -0700672 zips = (char**)realloc(zips, z_alloc * sizeof(char*));
Doug Zongker8674a722010-09-15 11:08:23 -0700673 }
674 zips[z_size++] = strdup(de->d_name);
675 }
676 }
677 closedir(d);
678
679 qsort(dirs, d_size, sizeof(char*), compare_string);
680 qsort(zips, z_size, sizeof(char*), compare_string);
681
682 // append dirs to the zips list
683 if (d_size + z_size + 1 > z_alloc) {
684 z_alloc = d_size + z_size + 1;
Doug Zongker28ce47c2011-10-28 10:33:05 -0700685 zips = (char**)realloc(zips, z_alloc * sizeof(char*));
Doug Zongker8674a722010-09-15 11:08:23 -0700686 }
687 memcpy(zips + z_size, dirs, d_size * sizeof(char*));
688 free(dirs);
689 z_size += d_size;
690 zips[z_size] = NULL;
691
692 int result;
693 int chosen_item = 0;
694 do {
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700695 chosen_item = get_menu_selection(headers, zips, 1, chosen_item, device);
Doug Zongker8674a722010-09-15 11:08:23 -0700696
697 char* item = zips[chosen_item];
698 int item_len = strlen(item);
699 if (chosen_item == 0) { // item 0 is always "../"
Michael Ward9d2629c2011-06-23 22:14:24 -0700700 // go up but continue browsing (if the caller is update_directory)
Doug Zongker8674a722010-09-15 11:08:23 -0700701 result = -1;
702 break;
703 } else if (item[item_len-1] == '/') {
704 // recurse down into a subdirectory
705 char new_path[PATH_MAX];
Doug Zongkerd4208f92010-09-20 12:16:13 -0700706 strlcpy(new_path, path, PATH_MAX);
707 strlcat(new_path, "/", PATH_MAX);
Doug Zongker8674a722010-09-15 11:08:23 -0700708 strlcat(new_path, item, PATH_MAX);
Doug Zongkerd4208f92010-09-20 12:16:13 -0700709 new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/'
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700710 result = update_directory(new_path, unmount_when_done, wipe_cache, device);
Doug Zongker8674a722010-09-15 11:08:23 -0700711 if (result >= 0) break;
712 } else {
713 // selected a zip file: attempt to install it, and return
714 // the status to the caller.
715 char new_path[PATH_MAX];
Doug Zongkerd4208f92010-09-20 12:16:13 -0700716 strlcpy(new_path, path, PATH_MAX);
Doug Zongkerc18eeb82010-09-21 16:49:26 -0700717 strlcat(new_path, "/", PATH_MAX);
Doug Zongker8674a722010-09-15 11:08:23 -0700718 strlcat(new_path, item, PATH_MAX);
719
Doug Zongker211aebc2011-10-28 15:13:10 -0700720 ui->Print("\n-- Install %s ...\n", path);
Doug Zongker8674a722010-09-15 11:08:23 -0700721 set_sdcard_update_bootloader_message();
Doug Zongkerd4208f92010-09-20 12:16:13 -0700722 char* copy = copy_sideloaded_package(new_path);
Michael Ward9d2629c2011-06-23 22:14:24 -0700723 if (unmount_when_done != NULL) {
724 ensure_path_unmounted(unmount_when_done);
725 }
Doug Zongkerd4208f92010-09-20 12:16:13 -0700726 if (copy) {
Doug Zongkerd0181b82011-10-19 10:51:12 -0700727 result = install_package(copy, wipe_cache, TEMPORARY_INSTALL_FILE);
Doug Zongkerd4208f92010-09-20 12:16:13 -0700728 free(copy);
729 } else {
730 result = INSTALL_ERROR;
731 }
Doug Zongker8674a722010-09-15 11:08:23 -0700732 break;
733 }
734 } while (true);
735
736 int i;
737 for (i = 0; i < z_size; ++i) free(zips[i]);
738 free(zips);
739 free(headers);
740
Michael Ward9d2629c2011-06-23 22:14:24 -0700741 if (unmount_when_done != NULL) {
742 ensure_path_unmounted(unmount_when_done);
743 }
Doug Zongker8674a722010-09-15 11:08:23 -0700744 return result;
745}
746
Doug Zongkerf93d8162009-09-22 15:16:02 -0700747static void
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700748wipe_data(int confirm, Device* device) {
Doug Zongkerf93d8162009-09-22 15:16:02 -0700749 if (confirm) {
Doug Zongker28ce47c2011-10-28 10:33:05 -0700750 static const char** title_headers = NULL;
Doug Zongkerddd6a282009-06-09 12:22:33 -0700751
Doug Zongkerf93d8162009-09-22 15:16:02 -0700752 if (title_headers == NULL) {
Doug Zongker28ce47c2011-10-28 10:33:05 -0700753 const char* headers[] = { "Confirm wipe of all user data?",
754 " THIS CAN NOT BE UNDONE.",
755 "",
756 NULL };
Doug Zongker8674a722010-09-15 11:08:23 -0700757 title_headers = prepend_title((const char**)headers);
Doug Zongkerf93d8162009-09-22 15:16:02 -0700758 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800759
Doug Zongker28ce47c2011-10-28 10:33:05 -0700760 const char* items[] = { " No",
761 " No",
762 " No",
763 " No",
764 " No",
765 " No",
766 " No",
767 " Yes -- delete all user data", // [7]
768 " No",
769 " No",
770 " No",
771 NULL };
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800772
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700773 int chosen_item = get_menu_selection(title_headers, items, 1, 0, device);
Doug Zongkerf93d8162009-09-22 15:16:02 -0700774 if (chosen_item != 7) {
775 return;
776 }
777 }
Doug Zongker1066d2c2009-04-01 13:57:40 -0700778
Doug Zongker211aebc2011-10-28 15:13:10 -0700779 ui->Print("\n-- Wiping data...\n");
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700780 device->WipeData();
Doug Zongkerd4208f92010-09-20 12:16:13 -0700781 erase_volume("/data");
782 erase_volume("/cache");
Doug Zongker211aebc2011-10-28 15:13:10 -0700783 ui->Print("Data wipe complete.\n");
Doug Zongkerf93d8162009-09-22 15:16:02 -0700784}
785
786static void
Doug Zongker6c8553d2012-09-24 10:40:47 -0700787prompt_and_wait(Device* device, int status) {
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700788 const char* const* headers = prepend_title(device->GetMenuHeaders());
Doug Zongkerf93d8162009-09-22 15:16:02 -0700789
790 for (;;) {
791 finish_recovery(NULL);
Doug Zongker6c8553d2012-09-24 10:40:47 -0700792 switch (status) {
793 case INSTALL_SUCCESS:
794 case INSTALL_NONE:
795 ui->SetBackground(RecoveryUI::NO_COMMAND);
796 break;
797
798 case INSTALL_ERROR:
799 case INSTALL_CORRUPT:
800 ui->SetBackground(RecoveryUI::ERROR);
801 break;
802 }
Doug Zongker211aebc2011-10-28 15:13:10 -0700803 ui->SetProgressType(RecoveryUI::EMPTY);
Doug Zongkerf93d8162009-09-22 15:16:02 -0700804
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700805 int chosen_item = get_menu_selection(headers, device->GetMenuItems(), 0, 0, device);
Doug Zongkerf93d8162009-09-22 15:16:02 -0700806
807 // device-specific code may take some action here. It may
808 // return one of the core actions handled in the switch
809 // statement below.
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700810 chosen_item = device->InvokeMenuItem(chosen_item);
Doug Zongkerf93d8162009-09-22 15:16:02 -0700811
Doug Zongkerd0181b82011-10-19 10:51:12 -0700812 int wipe_cache;
Doug Zongkerf93d8162009-09-22 15:16:02 -0700813 switch (chosen_item) {
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700814 case Device::REBOOT:
Doug Zongkerf93d8162009-09-22 15:16:02 -0700815 return;
816
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700817 case Device::WIPE_DATA:
818 wipe_data(ui->IsTextVisible(), device);
Doug Zongker211aebc2011-10-28 15:13:10 -0700819 if (!ui->IsTextVisible()) return;
Doug Zongkerf93d8162009-09-22 15:16:02 -0700820 break;
821
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700822 case Device::WIPE_CACHE:
Doug Zongker211aebc2011-10-28 15:13:10 -0700823 ui->Print("\n-- Wiping cache...\n");
Doug Zongkerd4208f92010-09-20 12:16:13 -0700824 erase_volume("/cache");
Doug Zongker211aebc2011-10-28 15:13:10 -0700825 ui->Print("Cache wipe complete.\n");
826 if (!ui->IsTextVisible()) return;
Doug Zongkerf93d8162009-09-22 15:16:02 -0700827 break;
828
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700829 case Device::APPLY_EXT:
830 status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device);
Doug Zongkerd0181b82011-10-19 10:51:12 -0700831 if (status == INSTALL_SUCCESS && wipe_cache) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700832 ui->Print("\n-- Wiping cache (at package request)...\n");
Doug Zongkerd0181b82011-10-19 10:51:12 -0700833 if (erase_volume("/cache")) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700834 ui->Print("Cache wipe failed.\n");
Doug Zongkerd0181b82011-10-19 10:51:12 -0700835 } else {
Doug Zongker211aebc2011-10-28 15:13:10 -0700836 ui->Print("Cache wipe complete.\n");
Doug Zongkerd0181b82011-10-19 10:51:12 -0700837 }
838 }
Doug Zongker8674a722010-09-15 11:08:23 -0700839 if (status >= 0) {
840 if (status != INSTALL_SUCCESS) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700841 ui->SetBackground(RecoveryUI::ERROR);
842 ui->Print("Installation aborted.\n");
843 } else if (!ui->IsTextVisible()) {
Doug Zongker8674a722010-09-15 11:08:23 -0700844 return; // reboot if logs aren't visible
845 } else {
Doug Zongker211aebc2011-10-28 15:13:10 -0700846 ui->Print("\nInstall from sdcard complete.\n");
Doug Zongker8674a722010-09-15 11:08:23 -0700847 }
Doug Zongkerf93d8162009-09-22 15:16:02 -0700848 }
849 break;
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700850
851 case Device::APPLY_CACHE:
Michael Ward9d2629c2011-06-23 22:14:24 -0700852 // Don't unmount cache at the end of this.
Doug Zongkerdaefc1d2011-10-31 09:34:15 -0700853 status = update_directory(CACHE_ROOT, NULL, &wipe_cache, device);
Doug Zongkerd0181b82011-10-19 10:51:12 -0700854 if (status == INSTALL_SUCCESS && wipe_cache) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700855 ui->Print("\n-- Wiping cache (at package request)...\n");
Doug Zongkerd0181b82011-10-19 10:51:12 -0700856 if (erase_volume("/cache")) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700857 ui->Print("Cache wipe failed.\n");
Doug Zongkerd0181b82011-10-19 10:51:12 -0700858 } else {
Doug Zongker211aebc2011-10-28 15:13:10 -0700859 ui->Print("Cache wipe complete.\n");
Doug Zongkerd0181b82011-10-19 10:51:12 -0700860 }
861 }
Michael Ward9d2629c2011-06-23 22:14:24 -0700862 if (status >= 0) {
863 if (status != INSTALL_SUCCESS) {
Doug Zongker211aebc2011-10-28 15:13:10 -0700864 ui->SetBackground(RecoveryUI::ERROR);
865 ui->Print("Installation aborted.\n");
866 } else if (!ui->IsTextVisible()) {
Michael Ward9d2629c2011-06-23 22:14:24 -0700867 return; // reboot if logs aren't visible
868 } else {
Doug Zongker211aebc2011-10-28 15:13:10 -0700869 ui->Print("\nInstall from cache complete.\n");
Michael Ward9d2629c2011-06-23 22:14:24 -0700870 }
871 }
872 break;
Doug Zongker9270a202012-01-09 15:16:13 -0800873
874 case Device::APPLY_ADB_SIDELOAD:
Doug Zongker9270a202012-01-09 15:16:13 -0800875 status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE);
876 if (status >= 0) {
877 if (status != INSTALL_SUCCESS) {
878 ui->SetBackground(RecoveryUI::ERROR);
879 ui->Print("Installation aborted.\n");
Doug Zongkerf24fd7e2013-07-02 11:43:25 -0700880 copy_logs();
Doug Zongker9270a202012-01-09 15:16:13 -0800881 } else if (!ui->IsTextVisible()) {
882 return; // reboot if logs aren't visible
883 } else {
884 ui->Print("\nInstall from ADB complete.\n");
885 }
886 }
887 break;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800888 }
889 }
890}
891
892static void
Oscar Montemayor05231562009-11-30 08:40:57 -0800893print_property(const char *key, const char *name, void *cookie) {
Doug Zongker56c51052010-07-01 09:18:44 -0700894 printf("%s=%s\n", key, name);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800895}
896
Doug Zongker02ec6b82012-08-22 17:26:40 -0700897static void
898load_locale_from_cache() {
899 FILE* fp = fopen_path(LOCALE_FILE, "r");
900 char buffer[80];
901 if (fp != NULL) {
902 fgets(buffer, sizeof(buffer), fp);
903 int j = 0;
Doug Zongker5fa8c232012-09-18 12:37:02 -0700904 unsigned int i;
Doug Zongker02ec6b82012-08-22 17:26:40 -0700905 for (i = 0; i < sizeof(buffer) && buffer[i]; ++i) {
906 if (!isspace(buffer[i])) {
907 buffer[j++] = buffer[i];
908 }
909 }
910 buffer[j] = 0;
911 locale = strdup(buffer);
Devin Kim6016d082012-10-08 09:47:37 -0700912 check_and_fclose(fp, LOCALE_FILE);
Doug Zongker02ec6b82012-08-22 17:26:40 -0700913 }
914}
915
Doug Zongker7c3ae452013-05-14 11:03:02 -0700916static RecoveryUI* gCurrentUI = NULL;
917
918void
919ui_print(const char* format, ...) {
920 char buffer[256];
921
922 va_list ap;
923 va_start(ap, format);
924 vsnprintf(buffer, sizeof(buffer), format, ap);
925 va_end(ap);
926
927 if (gCurrentUI != NULL) {
928 gCurrentUI->Print("%s", buffer);
929 } else {
930 fputs(buffer, stdout);
931 }
932}
933
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800934int
Oscar Montemayor05231562009-11-30 08:40:57 -0800935main(int argc, char **argv) {
Dees_Troycfb63ae2012-09-19 14:30:17 -0400936 // Recovery needs to install world-readable files, so clear umask
937 // set by init
938 umask(0);
939
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800940 time_t start = time(NULL);
941
942 // If these fail, there's not really anywhere to complain...
943 freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
944 freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
Doug Zongker9270a202012-01-09 15:16:13 -0800945
946 // If this binary is started with the single argument "--adbd",
947 // instead of being the normal recovery binary, it turns into kind
948 // of a stripped-down version of adbd that only supports the
949 // 'sideload' command. Note this must be a real argument, not
950 // anything in the command file or bootloader control block; the
951 // only way recovery should be run with this argument is when it
952 // starts a copy of itself from the apply_from_adb() function.
Dees_Troy9a4b5692012-09-19 15:09:45 -0400953 if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
954 adb_main(argv[2]);
Doug Zongker9270a202012-01-09 15:16:13 -0800955 return 0;
956 }
957
Dees_Troy51127312012-09-08 13:08:49 -0400958 printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&start));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800959
Dees_Troy32c8eb82012-09-11 15:28:06 -0400960 Device* device = make_device();
961 ui = device->GetUI();
Doug Zongker211aebc2011-10-28 15:13:10 -0700962
Dees_Troy7d15c252012-09-05 20:47:21 -0400963 //ui->Init();
964 //ui->SetBackground(RecoveryUI::NONE);
Dees_Troy7c2dec82012-09-26 09:49:14 -0400965 //load_volume_table();
Dees_Troy7d15c252012-09-05 20:47:21 -0400966
967 // Load default values to set DataManager constants and handle ifdefs
968 DataManager_LoadDefaults();
969 printf("Starting the UI...");
Dees_Troy51127312012-09-08 13:08:49 -0400970 gui_init();
Dees_Troy7d15c252012-09-05 20:47:21 -0400971 printf("=> Linking mtab\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500972 symlink("/proc/mounts", "/etc/mtab");
Dees_Troy7d15c252012-09-05 20:47:21 -0400973 printf("=> Processing recovery.fstab\n");
Dees_Troy5bf43922012-09-07 16:07:55 -0400974 if (!PartitionManager.Process_Fstab("/etc/recovery.fstab", 1)) {
Dees_Troy7d15c252012-09-05 20:47:21 -0400975 LOGE("Failing out of recovery due to problem with recovery.fstab.\n");
976 //return -1;
977 }
Dees_Troy8170a922012-09-18 15:40:25 -0400978 PartitionManager.Output_Partition_Logging();
Dees_Troy7d15c252012-09-05 20:47:21 -0400979 // Load up all the resources
980 gui_loadResources();
981
Dees_Troy01b6d0c2013-01-22 01:41:09 +0000982 PartitionManager.Mount_By_Path("/cache", true);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800983
Doug Zongkerd4208f92010-09-20 12:16:13 -0700984 load_volume_table();
Doug Zongkerda1ebae2013-05-16 11:23:48 -0700985 ensure_path_mounted(LAST_LOG_FILE);
Dees_Troy1669f892013-09-04 18:35:08 +0000986
Doug Zongkerf24fd7e2013-07-02 11:43:25 -0700987 rotate_last_logs(10);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800988 get_args(&argc, &argv);
989
990 int previous_runs = 0;
991 const char *send_intent = NULL;
992 const char *update_package = NULL;
Doug Zongker02ec6b82012-08-22 17:26:40 -0700993 int wipe_data = 0, wipe_cache = 0, show_text = 0;
Doug Zongkere5d5ac72012-04-12 11:01:22 -0700994 bool just_exit = false;
Dees_Troy83a3b122012-10-01 14:16:43 -0400995 bool perform_backup = false;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800996
997 int arg;
998 while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
999 switch (arg) {
1000 case 'p': previous_runs = atoi(optarg); break;
1001 case 's': send_intent = optarg; break;
1002 case 'u': update_package = optarg; break;
1003 case 'w': wipe_data = wipe_cache = 1; break;
1004 case 'c': wipe_cache = 1; break;
Doug Zongker02ec6b82012-08-22 17:26:40 -07001005 case 't': show_text = 1; break;
Doug Zongkere5d5ac72012-04-12 11:01:22 -07001006 case 'x': just_exit = true; break;
Doug Zongker02ec6b82012-08-22 17:26:40 -07001007 case 'l': locale = optarg; break;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001008 case '?':
1009 LOGE("Invalid command argument\n");
1010 continue;
1011 }
1012 }
1013
Doug Zongker02ec6b82012-08-22 17:26:40 -07001014 if (locale == NULL) {
1015 load_locale_from_cache();
1016 }
1017 printf("locale is [%s]\n", locale);
1018
1019 Device* device = make_device();
1020 ui = device->GetUI();
Doug Zongker7c3ae452013-05-14 11:03:02 -07001021 gCurrentUI = ui;
Doug Zongker02ec6b82012-08-22 17:26:40 -07001022
1023 ui->Init();
Doug Zongker5fa8c232012-09-18 12:37:02 -07001024 ui->SetLocale(locale);
Doug Zongker02ec6b82012-08-22 17:26:40 -07001025 ui->SetBackground(RecoveryUI::NONE);
1026 if (show_text) ui->ShowText(true);
1027
Stephen Smalley779701d2012-02-09 14:13:23 -05001028 struct selinux_opt seopts[] = {
1029 { SELABEL_OPT_PATH, "/file_contexts" }
1030 };
1031
1032 sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
1033
1034 if (!sehandle) {
Doug Zongkerfafc85b2013-07-09 12:29:45 -07001035 ui->Print("Warning: No file_contexts\n");
Stephen Smalley779701d2012-02-09 14:13:23 -05001036 }
Stephen Smalley779701d2012-02-09 14:13:23 -05001037
Dees_Troy7d15c252012-09-05 20:47:21 -04001038 //device->StartRecovery();
Doug Zongkerefa1bab2010-02-01 15:59:12 -08001039
Doug Zongker56c51052010-07-01 09:18:44 -07001040 printf("Command:");
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001041 for (arg = 0; arg < argc; arg++) {
Doug Zongker56c51052010-07-01 09:18:44 -07001042 printf(" \"%s\"", argv[arg]);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001043 }
Doug Zongker9b125b02010-09-22 12:01:37 -07001044 printf("\n");
1045
1046 if (update_package) {
1047 // For backwards compatibility on the cache partition only, if
1048 // we're given an old 'root' path "CACHE:foo", change it to
1049 // "/cache/foo".
1050 if (strncmp(update_package, "CACHE:", 6) == 0) {
1051 int len = strlen(update_package) + 10;
Doug Zongker28ce47c2011-10-28 10:33:05 -07001052 char* modified_path = (char*)malloc(len);
Doug Zongker9b125b02010-09-22 12:01:37 -07001053 strlcpy(modified_path, "/cache/", len);
1054 strlcat(modified_path, update_package+6, len);
1055 printf("(replacing path \"%s\" with \"%s\")\n",
1056 update_package, modified_path);
1057 update_package = modified_path;
1058 }
1059 }
1060 printf("\n");
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001061
1062 property_list(print_property, NULL);
Doug Zongkerc0441d12013-07-31 11:28:24 -07001063 property_get("ro.build.display.id", recovery_version, "");
Doug Zongker56c51052010-07-01 09:18:44 -07001064 printf("\n");
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001065
Dees_Troy7d15c252012-09-05 20:47:21 -04001066 // Check for and run startup script if script exists
Dees_Troya58bead2012-09-27 09:49:29 -04001067 TWFunc::check_and_run_script("/sbin/runatboot.sh", "boot");
1068 TWFunc::check_and_run_script("/sbin/postrecoveryboot.sh", "boot");
Dees_Troy7d15c252012-09-05 20:47:21 -04001069
1070#ifdef TW_INCLUDE_INJECTTWRP
1071 // Back up TWRP Ramdisk if needed:
Dees_Troy06b4fe92012-10-16 11:43:20 -04001072 TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot");
Dees_Troy7d15c252012-09-05 20:47:21 -04001073 LOGI("Backing up TWRP ramdisk...\n");
Dees_Troy06b4fe92012-10-16 11:43:20 -04001074 if (Boot == NULL || Boot->Current_File_System != "emmc")
Vojtech Bocek05534202013-09-11 08:11:56 +02001075 TWFunc::Exec_Cmd("injecttwrp --backup /tmp/backup_recovery_ramdisk.img");
Dees_Troy06b4fe92012-10-16 11:43:20 -04001076 else {
1077 string injectcmd = "injecttwrp --backup /tmp/backup_recovery_ramdisk.img bd=" + Boot->Actual_Block_Device;
Vojtech Bocek05534202013-09-11 08:11:56 +02001078 TWFunc::Exec_Cmd(injectcmd);
Dees_Troy06b4fe92012-10-16 11:43:20 -04001079 }
Dees_Troy7d15c252012-09-05 20:47:21 -04001080 LOGI("Backup of TWRP ramdisk done.\n");
1081#endif
1082
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001083 int status = INSTALL_SUCCESS;
Dees_Troy01b6d0c2013-01-22 01:41:09 +00001084 string ORSCommand;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001085
Dees_Troy83a3b122012-10-01 14:16:43 -04001086 if (perform_backup) {
1087 char empt[50];
1088 gui_console_only();
1089 strcpy(empt, "(Current Date)");
1090 DataManager_SetStrValue(TW_BACKUP_NAME, empt);
Dees_Troy01b6d0c2013-01-22 01:41:09 +00001091 if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n"))
Dees_Troy83a3b122012-10-01 14:16:43 -04001092 status = INSTALL_ERROR;
1093 }
1094 if (status == INSTALL_SUCCESS) { // Prevent other actions if backup failed
Doug Zongker540d57f2011-01-18 13:36:58 -08001095 if (update_package != NULL) {
Dees_Troy01b6d0c2013-01-22 01:41:09 +00001096 ORSCommand = "install ";
1097 ORSCommand += update_package;
1098 ORSCommand += "\n";
1099
1100 if (OpenRecoveryScript::Insert_ORS_Command(ORSCommand))
Dees_Troy83a3b122012-10-01 14:16:43 -04001101 status = INSTALL_SUCCESS;
1102 else
1103 status = INSTALL_ERROR;
1104 /*
Doug Zongkerd0181b82011-10-19 10:51:12 -07001105 status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
1106 if (status == INSTALL_SUCCESS && wipe_cache) {
1107 if (erase_volume("/cache")) {
1108 LOGE("Cache wipe (requested by package) failed.");
1109 }
1110 }
Dees_Troy1669f892013-09-04 18:35:08 +00001111
Doug Zongker7c3ae452013-05-14 11:03:02 -07001112 if (status != INSTALL_SUCCESS) {
1113 ui->Print("Installation aborted.\n");
1114
1115 // If this is an eng or userdebug build, then automatically
1116 // turn the text display on if the script fails so the error
1117 // message is visible.
1118 char buffer[PROPERTY_VALUE_MAX+1];
1119 property_get("ro.build.fingerprint", buffer, "");
1120 if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) {
1121 ui->ShowText(true);
1122 }
1123 }
Doug Zongkerb128f542009-06-18 15:07:14 -07001124 } else if (wipe_data) {
Dees_Troy01b6d0c2013-01-22 01:41:09 +00001125 if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
1126 status = INSTALL_ERROR;
Dees_Troy83a3b122012-10-01 14:16:43 -04001127 /*
1128 if (device->WipeData()) status = INSTALL_ERROR;
1129 if (erase_volume("/data")) status = INSTALL_ERROR;
1130 if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
1131 */
Doug Zongker211aebc2011-10-28 15:13:10 -07001132 if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
Doug Zongkerb128f542009-06-18 15:07:14 -07001133 } else if (wipe_cache) {
Dees_Troy01b6d0c2013-01-22 01:41:09 +00001134 if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n"))
1135 status = INSTALL_ERROR;
Doug Zongker211aebc2011-10-28 15:13:10 -07001136 if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
Doug Zongkere5d5ac72012-04-12 11:01:22 -07001137 } else if (!just_exit) {
Doug Zongker02ec6b82012-08-22 17:26:40 -07001138 status = INSTALL_NONE; // No command specified
1139 ui->SetBackground(RecoveryUI::NO_COMMAND);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001140 }
Dees_Troy83a3b122012-10-01 14:16:43 -04001141 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001142
Dees_Troyd15e3f72013-02-21 14:28:29 -06001143 finish_recovery(NULL);
1144 // Offer to decrypt if the device is encrypted
1145 if (DataManager_GetIntValue(TW_IS_ENCRYPTED) != 0) {
1146 LOGI("Is encrypted, do decrypt page first\n");
1147 if (gui_startPage("decrypt") != 0) {
1148 LOGE("Failed to start decrypt GUI page.\n");
Dees_Troyc7c43412012-10-02 23:03:01 -04001149 }
Dees_Troyd15e3f72013-02-21 14:28:29 -06001150 }
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001151
Dees_Troyd15e3f72013-02-21 14:28:29 -06001152 // Read the settings file
1153 DataManager_ReadSettingsFile();
1154 // Run any outstanding OpenRecoveryScript
1155 if (DataManager_GetIntValue(TW_IS_ENCRYPTED) == 0 && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(SCRIPT_FILE_CACHE))) {
1156 OpenRecoveryScript::Run_OpenRecoveryScript();
1157 }
1158 // Launch the main GUI
1159 gui_start();
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001160
Dees_Troy6ef66352013-02-21 08:26:57 -06001161 // Check for su to see if the device is rooted or not
1162 if (PartitionManager.Mount_By_Path("/system", false)) {
Dees_Troyd15e3f72013-02-21 14:28:29 -06001163 // Disable flashing of stock recovery
dhacker2930f100e2014-07-15 21:33:29 -04001164 if (TWFunc::Path_Exists("/system/recovery-from-boot.p") && TWFunc::Path_Exists("/system/etc/install-recovery.sh")) {
Dees_Troyd15e3f72013-02-21 14:28:29 -06001165 rename("/system/recovery-from-boot.p", "/system/recovery-from-boot.bak");
1166 ui_print("Renamed stock recovery file in /system to prevent\nthe stock ROM from replacing TWRP.\n");
1167 }
jt1134113ee732013-02-22 23:26:10 -06001168 if (TWFunc::Path_Exists("/supersu/su") && !TWFunc::Path_Exists("/system/bin/su") && !TWFunc::Path_Exists("/system/xbin/su") && !TWFunc::Path_Exists("/system/bin/.ext/.su")) {
Dees_Troy6ef66352013-02-21 08:26:57 -06001169 // Device doesn't have su installed
1170 DataManager_SetIntValue("tw_busy", 1);
1171 if (gui_startPage("installsu") != 0) {
1172 LOGE("Failed to start decrypt GUI page.\n");
1173 }
1174 } else if (TWFunc::Check_su_Perms() > 0) {
1175 // su perms are set incorrectly
1176 DataManager_SetIntValue("tw_busy", 1);
1177 if (gui_startPage("fixsu") != 0) {
1178 LOGE("Failed to start decrypt GUI page.\n");
1179 }
1180 }
Dees_Troyd15e3f72013-02-21 14:28:29 -06001181 sync();
1182 PartitionManager.UnMount_By_Path("/system", false);
Dees_Troy6ef66352013-02-21 08:26:57 -06001183 }
1184
Doug Zongker02ec6b82012-08-22 17:26:40 -07001185 if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
Doug Zongkerf24fd7e2013-07-02 11:43:25 -07001186 copy_logs();
Doug Zongker02ec6b82012-08-22 17:26:40 -07001187 ui->SetBackground(RecoveryUI::ERROR);
1188 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001189 if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
Doug Zongker6c8553d2012-09-24 10:40:47 -07001190 prompt_and_wait(device, status);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001191 }
1192
1193 // Otherwise, get ready to boot the main system...
1194 finish_recovery(send_intent);
Doug Zongker211aebc2011-10-28 15:13:10 -07001195 ui->Print("Rebooting...\n");
Dees_Troy6ef66352013-02-21 08:26:57 -06001196 char backup_arg_char[50];
1197 strcpy(backup_arg_char, DataManager_GetStrValue("tw_reboot_arg"));
1198 string backup_arg = backup_arg_char;
1199 if (backup_arg == "recovery")
1200 TWFunc::tw_reboot(rb_recovery);
1201 else if (backup_arg == "poweroff")
1202 TWFunc::tw_reboot(rb_poweroff);
1203 else if (backup_arg == "bootloader")
1204 TWFunc::tw_reboot(rb_bootloader);
1205 else if (backup_arg == "download")
1206 TWFunc::tw_reboot(rb_download);
1207 else
1208 TWFunc::tw_reboot(rb_system);
1209
Dees_Troy38bd7602012-09-14 13:33:53 -04001210#ifdef ANDROID_RB_RESTART
Ken Sumrall6e4472a2011-03-07 23:37:27 -08001211 android_reboot(ANDROID_RB_RESTART, 0, 0);
Dees_Troy38bd7602012-09-14 13:33:53 -04001212#else
1213 reboot(RB_AUTOBOOT);
1214#endif
Doug Zongker3b5a9872013-09-03 14:29:54 -07001215 property_set(ANDROID_RB_PROPERTY, "reboot,");
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001216 return EXIT_SUCCESS;
1217}