xref: /OK3568_Linux_fs/external/recovery/recovery.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2007 The Android Open Source Project
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Licensed under the Apache License, Version 2.0 (the "License");
5*4882a593Smuzhiyun  * you may not use this file except in compliance with the License.
6*4882a593Smuzhiyun  * You may obtain a copy of the License at
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *      http://www.apache.org/licenses/LICENSE-2.0
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Unless required by applicable law or agreed to in writing, software
11*4882a593Smuzhiyun  * distributed under the License is distributed on an "AS IS" BASIS,
12*4882a593Smuzhiyun  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4882a593Smuzhiyun  * See the License for the specific language governing permissions and
14*4882a593Smuzhiyun  * limitations under the License.
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <ctype.h>
18*4882a593Smuzhiyun #include <errno.h>
19*4882a593Smuzhiyun #include <fcntl.h>
20*4882a593Smuzhiyun #include <getopt.h>
21*4882a593Smuzhiyun #include <limits.h>
22*4882a593Smuzhiyun #include <linux/input.h>
23*4882a593Smuzhiyun #include <stdio.h>
24*4882a593Smuzhiyun #include <stdlib.h>
25*4882a593Smuzhiyun #include <string.h>
26*4882a593Smuzhiyun #include <sys/reboot.h>
27*4882a593Smuzhiyun #include <sys/stat.h>
28*4882a593Smuzhiyun #include <sys/types.h>
29*4882a593Smuzhiyun #include <time.h>
30*4882a593Smuzhiyun #include <unistd.h>
31*4882a593Smuzhiyun #include <dirent.h>
32*4882a593Smuzhiyun #include <sys/time.h>
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #include "bootloader.h"
35*4882a593Smuzhiyun #include "common.h"
36*4882a593Smuzhiyun //#include "cutils/properties.h"
37*4882a593Smuzhiyun #include "install.h"
38*4882a593Smuzhiyun #include "minui/minui.h"
39*4882a593Smuzhiyun #include "minzip/DirUtil.h"
40*4882a593Smuzhiyun #include "roots.h"
41*4882a593Smuzhiyun #include "recovery_ui.h"
42*4882a593Smuzhiyun #include "encryptedfs_provisioning.h"
43*4882a593Smuzhiyun #include "rktools.h"
44*4882a593Smuzhiyun #include "sdboot.h"
45*4882a593Smuzhiyun #include "usbboot.h"
46*4882a593Smuzhiyun #include "mtdutils/mtdutils.h"
47*4882a593Smuzhiyun #include "recovery_version.h"
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun static const char *recovery_version = RECOVERY_VERSION_STRING;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun static const struct option OPTIONS[] = {
52*4882a593Smuzhiyun     { "send_intent", required_argument, NULL, 's' },
53*4882a593Smuzhiyun     { "update_package", required_argument, NULL, 'u' },
54*4882a593Smuzhiyun     { "wipe_data", no_argument, NULL, 'w' },
55*4882a593Smuzhiyun     { "wipe_all", no_argument, NULL, 'a' },
56*4882a593Smuzhiyun     { "set_encrypted_filesystems", required_argument, NULL, 'e' },
57*4882a593Smuzhiyun     { "show_text", no_argument, NULL, 't' },
58*4882a593Smuzhiyun     { "factory_pcba_test", no_argument, NULL, 'f' },
59*4882a593Smuzhiyun     { "rkdebug", no_argument, NULL, 'r'},
60*4882a593Smuzhiyun     { "ui_rotation", required_argument, NULL, 'i'},
61*4882a593Smuzhiyun     { NULL, 0, NULL, 0 },
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun static const char *COMMAND_FILE = "/userdata/recovery/command";
65*4882a593Smuzhiyun static const char *INTENT_FILE = "/userdata/recovery/intent";
66*4882a593Smuzhiyun static const char *LOG_FILE = "/userdata/recovery/log";
67*4882a593Smuzhiyun static const char *LAST_LOG_FILE = "/userdata/recovery/last_log";
68*4882a593Smuzhiyun static const char *SDCARD_ROOT = "/sdcard";
69*4882a593Smuzhiyun static const char *SDCARD_ROOT2 = "/mnt/external_sd";
70*4882a593Smuzhiyun static const char *USERDATA_ROOT = "/userdata";
71*4882a593Smuzhiyun static const char *UDISK_ROOT = "/udisk";
72*4882a593Smuzhiyun static const char *UDISK_ROOT2 = "/mnt/usb_storage";
73*4882a593Smuzhiyun static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
74*4882a593Smuzhiyun static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
75*4882a593Smuzhiyun static const char *coldboot_done = "/dev/.coldboot_done";
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun char systemFlag[252];
78*4882a593Smuzhiyun bool bSDBootUpdate = false;
79*4882a593Smuzhiyun bool bUdiskUpdate  = false;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /*
82*4882a593Smuzhiyun  * The recovery tool communicates with the main system through /cache files.
83*4882a593Smuzhiyun  *   /cache/recovery/command - INPUT - command line for tool, one arg per line
84*4882a593Smuzhiyun  *   /cache/recovery/log - OUTPUT - combined log file from recovery run(s)
85*4882a593Smuzhiyun  *   /cache/recovery/intent - OUTPUT - intent that was passed in
86*4882a593Smuzhiyun  *
87*4882a593Smuzhiyun  * The arguments which may be supplied in the recovery.command file:
88*4882a593Smuzhiyun  *   --send_intent=anystring - write the text out to recovery.intent
89*4882a593Smuzhiyun  *   --update_package=path - verify install an OTA package file
90*4882a593Smuzhiyun  *   --wipe_data - erase user data (and cache), then reboot
91*4882a593Smuzhiyun  *   --wipe_cache - wipe cache (but not user data), then reboot
92*4882a593Smuzhiyun  *   --set_encrypted_filesystem=on|off - enables / diasables encrypted fs
93*4882a593Smuzhiyun  *
94*4882a593Smuzhiyun  * After completing, we remove /cache/recovery/command and reboot.
95*4882a593Smuzhiyun  * Arguments may also be supplied in the bootloader control block (BCB).
96*4882a593Smuzhiyun  * These important scenarios must be safely restartable at any point:
97*4882a593Smuzhiyun  *
98*4882a593Smuzhiyun  * FACTORY RESET
99*4882a593Smuzhiyun  * 1. user selects "factory reset"
100*4882a593Smuzhiyun  * 2. main system writes "--wipe_data" to /cache/recovery/command
101*4882a593Smuzhiyun  * 3. main system reboots into recovery
102*4882a593Smuzhiyun  * 4. get_args() writes BCB with "boot-recovery" and "--wipe_data"
103*4882a593Smuzhiyun  *    -- after this, rebooting will restart the erase --
104*4882a593Smuzhiyun  * 5. erase_volume() reformats /userdata
105*4882a593Smuzhiyun  * 6. erase_volume() reformats /cache
106*4882a593Smuzhiyun  * 7. finish_recovery() erases BCB
107*4882a593Smuzhiyun  *    -- after this, rebooting will restart the main system --
108*4882a593Smuzhiyun  * 8. main() calls reboot() to boot main system
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * OTA INSTALL
111*4882a593Smuzhiyun  * 1. main system downloads OTA package to /cache/some-filename.zip
112*4882a593Smuzhiyun  * 2. main system writes "--update_package=/cache/some-filename.zip"
113*4882a593Smuzhiyun  * 3. main system reboots into recovery
114*4882a593Smuzhiyun  * 4. get_args() writes BCB with "boot-recovery" and "--update_package=..."
115*4882a593Smuzhiyun  *    -- after this, rebooting will attempt to reinstall the update --
116*4882a593Smuzhiyun  * 5. install_package() attempts to install the update
117*4882a593Smuzhiyun  *    NOTE: the package install must itself be restartable from any point
118*4882a593Smuzhiyun  * 6. finish_recovery() erases BCB
119*4882a593Smuzhiyun  *    -- after this, rebooting will (try to) restart the main system --
120*4882a593Smuzhiyun  * 7. ** if install failed **
121*4882a593Smuzhiyun  *    7a. prompt_and_wait() shows an error icon and waits for the user
122*4882a593Smuzhiyun  *    7b; the user reboots (pulling the battery, etc) into the main system
123*4882a593Smuzhiyun  * 8. main() calls maybe_install_firmware_update()
124*4882a593Smuzhiyun  *    ** if the update contained radio/hboot firmware **:
125*4882a593Smuzhiyun  *    8a. m_i_f_u() writes BCB with "boot-recovery" and "--wipe_cache"
126*4882a593Smuzhiyun  *        -- after this, rebooting will reformat cache & restart main system --
127*4882a593Smuzhiyun  *    8b. m_i_f_u() writes firmware image into raw cache partition
128*4882a593Smuzhiyun  *    8c. m_i_f_u() writes BCB with "update-radio/hboot" and "--wipe_cache"
129*4882a593Smuzhiyun  *        -- after this, rebooting will attempt to reinstall firmware --
130*4882a593Smuzhiyun  *    8d. bootloader tries to flash firmware
131*4882a593Smuzhiyun  *    8e. bootloader writes BCB with "boot-recovery" (keeping "--wipe_cache")
132*4882a593Smuzhiyun  *        -- after this, rebooting will reformat cache & restart main system --
133*4882a593Smuzhiyun  *    8f. erase_volume() reformats /cache
134*4882a593Smuzhiyun  *    8g. finish_recovery() erases BCB
135*4882a593Smuzhiyun  *        -- after this, rebooting will (try to) restart the main system --
136*4882a593Smuzhiyun  * 9. main() calls reboot() to boot main system
137*4882a593Smuzhiyun  *
138*4882a593Smuzhiyun  * SECURE FILE SYSTEMS ENABLE/DISABLE
139*4882a593Smuzhiyun  * 1. user selects "enable encrypted file systems"
140*4882a593Smuzhiyun  * 2. main system writes "--set_encrypted_filesystems=on|off" to
141*4882a593Smuzhiyun  *    /cache/recovery/command
142*4882a593Smuzhiyun  * 3. main system reboots into recovery
143*4882a593Smuzhiyun  * 4. get_args() writes BCB with "boot-recovery" and
144*4882a593Smuzhiyun  *    "--set_encrypted_filesystems=on|off"
145*4882a593Smuzhiyun  *    -- after this, rebooting will restart the transition --
146*4882a593Smuzhiyun  * 5. read_encrypted_fs_info() retrieves encrypted file systems settings from /userdata
147*4882a593Smuzhiyun  *    Settings include: property to specify the Encrypted FS istatus and
148*4882a593Smuzhiyun  *    FS encryption key if enabled (not yet implemented)
149*4882a593Smuzhiyun  * 6. erase_volume() reformats /userdata
150*4882a593Smuzhiyun  * 7. erase_volume() reformats /cache
151*4882a593Smuzhiyun  * 8. restore_encrypted_fs_info() writes required encrypted file systems settings to /userdata
152*4882a593Smuzhiyun  *    Settings include: property to specify the Encrypted FS status and
153*4882a593Smuzhiyun  *    FS encryption key if enabled (not yet implemented)
154*4882a593Smuzhiyun  * 9. finish_recovery() erases BCB
155*4882a593Smuzhiyun  *    -- after this, rebooting will restart the main system --
156*4882a593Smuzhiyun  * 10. main() calls reboot() to boot main system
157*4882a593Smuzhiyun  */
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun static const int MAX_ARG_LENGTH = 4096;
160*4882a593Smuzhiyun static const int MAX_ARGS = 100;
161*4882a593Smuzhiyun extern size_t strlcpy(char *dst, const char *src, size_t dsize);
162*4882a593Smuzhiyun extern size_t strlcat(char *dst, const char *src, size_t dsize);
163*4882a593Smuzhiyun extern int do_rk_updateEngine(const char *binary, const char *path);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 
read_encrypted_fs_info(encrypted_fs_info * encrypted_fs_data)166*4882a593Smuzhiyun int read_encrypted_fs_info(encrypted_fs_info *encrypted_fs_data)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun     return ENCRYPTED_FS_ERROR;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
restore_encrypted_fs_info(encrypted_fs_info * encrypted_fs_data)171*4882a593Smuzhiyun int restore_encrypted_fs_info(encrypted_fs_info *encrypted_fs_data)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun     return ENCRYPTED_FS_ERROR;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun // open a given path, mounting partitions as necessary
176*4882a593Smuzhiyun static FILE*
fopen_path(const char * path,const char * mode)177*4882a593Smuzhiyun fopen_path(const char *path, const char *mode)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun     if (ensure_path_mounted(path) != 0) {
180*4882a593Smuzhiyun         LOGE("Can't mount %s\n", path);
181*4882a593Smuzhiyun         return NULL;
182*4882a593Smuzhiyun     }
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun     // When writing, try to create the containing directory, if necessary.
185*4882a593Smuzhiyun     // Use generous permissions, the system (init.rc) will reset them.
186*4882a593Smuzhiyun     if (strchr("wa", mode[0])) dirCreateHierarchy(path, 0777, NULL, 1);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun     FILE *fp = fopen(path, mode);
189*4882a593Smuzhiyun     return fp;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun // close a file, log an error if the error indicator is set
193*4882a593Smuzhiyun static void
check_and_fclose(FILE * fp,const char * name)194*4882a593Smuzhiyun check_and_fclose(FILE *fp, const char *name)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun     fflush(fp);
197*4882a593Smuzhiyun     if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
198*4882a593Smuzhiyun     fclose(fp);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun // rockchip partition check (e.g: oem/userdata....)
202*4882a593Smuzhiyun static void
rockchip_partition_check()203*4882a593Smuzhiyun rockchip_partition_check()
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun     if (ensure_path_unmounted("/oem") != 0)
206*4882a593Smuzhiyun         LOGE("\n === umount oem fail === \n");
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun     if (ensure_path_unmounted("/userdata") != 0)
209*4882a593Smuzhiyun         LOGE("\n === umount userdata fail === \n");
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun     ui_print("check userdata/oem partition success ...\n");
212*4882a593Smuzhiyun     LOGI("check userdata/oem partition success ...\n");
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun // command line args come from, in decreasing precedence:
216*4882a593Smuzhiyun //   - the actual command line
217*4882a593Smuzhiyun //   - the bootloader control block (one per line, after "recovery")
218*4882a593Smuzhiyun //   - the contents of COMMAND_FILE (one per line)
219*4882a593Smuzhiyun static void
get_args(int * argc,char *** argv)220*4882a593Smuzhiyun get_args(int *argc, char ***argv)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun     struct bootloader_message boot;
223*4882a593Smuzhiyun     memset(&boot, 0, sizeof(boot));
224*4882a593Smuzhiyun     get_bootloader_message(&boot);  // this may fail, leaving a zeroed structure
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun     if (boot.command[0] != 0 && boot.command[0] != 255) {
227*4882a593Smuzhiyun         LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
228*4882a593Smuzhiyun     }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun     if (boot.status[0] != 0 && boot.status[0] != 255) {
231*4882a593Smuzhiyun         LOGI("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
232*4882a593Smuzhiyun     }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun     // --- if arguments weren't supplied, look in the bootloader control block
235*4882a593Smuzhiyun     if (*argc <= 1) {
236*4882a593Smuzhiyun         boot.recovery[sizeof(boot.recovery) - 1] = '\0';  // Ensure termination
237*4882a593Smuzhiyun         const char *arg = strtok(boot.recovery, "\n");
238*4882a593Smuzhiyun         if (arg != NULL && !strcmp(arg, "recovery")) {
239*4882a593Smuzhiyun             *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
240*4882a593Smuzhiyun             (*argv)[0] = strdup(arg);
241*4882a593Smuzhiyun             for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
242*4882a593Smuzhiyun                 if ((arg = strtok(NULL, "\n")) == NULL) break;
243*4882a593Smuzhiyun                 (*argv)[*argc] = strdup(arg);
244*4882a593Smuzhiyun             }
245*4882a593Smuzhiyun             LOGI("Got arguments from boot message\n");
246*4882a593Smuzhiyun         } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
247*4882a593Smuzhiyun             LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
248*4882a593Smuzhiyun         }
249*4882a593Smuzhiyun     }
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun     // --- if that doesn't work, try the command file
252*4882a593Smuzhiyun     if (*argc <= 1) {
253*4882a593Smuzhiyun         FILE *fp = fopen_path(COMMAND_FILE, "r");
254*4882a593Smuzhiyun         if (fp != NULL) {
255*4882a593Smuzhiyun             char *argv0 = (*argv)[0];
256*4882a593Smuzhiyun             *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
257*4882a593Smuzhiyun             (*argv)[0] = argv0;  // use the same program name
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun             char buf[MAX_ARG_LENGTH];
260*4882a593Smuzhiyun             for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
261*4882a593Smuzhiyun                 if (!fgets(buf, sizeof(buf), fp)) break;
262*4882a593Smuzhiyun                 (*argv)[*argc] = strdup(strtok(buf, "\r\n"));  // Strip newline.
263*4882a593Smuzhiyun             }
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun             check_and_fclose(fp, COMMAND_FILE);
266*4882a593Smuzhiyun             LOGI("Got arguments from %s\n", COMMAND_FILE);
267*4882a593Smuzhiyun         }
268*4882a593Smuzhiyun     }
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun     // --> write the arguments we have back into the bootloader control block
271*4882a593Smuzhiyun     // always boot into recovery after this (until finish_recovery() is called)
272*4882a593Smuzhiyun     strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
273*4882a593Smuzhiyun     strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
274*4882a593Smuzhiyun     int i;
275*4882a593Smuzhiyun     for (i = 1; i < *argc; ++i) {
276*4882a593Smuzhiyun         strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
277*4882a593Smuzhiyun         strlcat(boot.recovery, "\n", sizeof(boot.recovery));
278*4882a593Smuzhiyun     }
279*4882a593Smuzhiyun     set_bootloader_message(&boot);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun static void
set_sdcard_update_bootloader_message()283*4882a593Smuzhiyun set_sdcard_update_bootloader_message()
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun     struct bootloader_message boot;
286*4882a593Smuzhiyun     memset(&boot, 0, sizeof(boot));
287*4882a593Smuzhiyun     strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
288*4882a593Smuzhiyun     strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
289*4882a593Smuzhiyun     set_bootloader_message(&boot);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun // How much of the temp log we have copied to the copy in cache.
293*4882a593Smuzhiyun static long tmplog_offset = 0;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun static void
copy_log_file(const char * destination,int append)296*4882a593Smuzhiyun copy_log_file(const char* destination, int append)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun     FILE *log = fopen_path(destination, append ? "a" : "w");
299*4882a593Smuzhiyun     if (log == NULL) {
300*4882a593Smuzhiyun         LOGE("Can't open %s\n", destination);
301*4882a593Smuzhiyun     } else {
302*4882a593Smuzhiyun         FILE *tmplog = fopen(TEMPORARY_LOG_FILE, "r");
303*4882a593Smuzhiyun         if (tmplog == NULL) {
304*4882a593Smuzhiyun             LOGE("Can't open %s\n", TEMPORARY_LOG_FILE);
305*4882a593Smuzhiyun         } else {
306*4882a593Smuzhiyun             if (append) {
307*4882a593Smuzhiyun                 fseek(tmplog, tmplog_offset, SEEK_SET);  // Since last write
308*4882a593Smuzhiyun             }
309*4882a593Smuzhiyun             char buf[4096];
310*4882a593Smuzhiyun             while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log);
311*4882a593Smuzhiyun             if (append) {
312*4882a593Smuzhiyun                 tmplog_offset = ftell(tmplog);
313*4882a593Smuzhiyun             }
314*4882a593Smuzhiyun             check_and_fclose(tmplog, TEMPORARY_LOG_FILE);
315*4882a593Smuzhiyun         }
316*4882a593Smuzhiyun         check_and_fclose(log, destination);
317*4882a593Smuzhiyun     }
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun // clear the recovery command and prepare to boot a (hopefully working) system,
322*4882a593Smuzhiyun // copy our log file to cache as well (for the system to read), and
323*4882a593Smuzhiyun // record any intent we were asked to communicate back to the system.
324*4882a593Smuzhiyun // this function is idempotent: call it as many times as you like.
325*4882a593Smuzhiyun static void
finish_recovery(const char * send_intent)326*4882a593Smuzhiyun finish_recovery(const char *send_intent)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun     // By this point, we're ready to return to the main system...
329*4882a593Smuzhiyun     if (send_intent != NULL) {
330*4882a593Smuzhiyun         FILE *fp = fopen_path(INTENT_FILE, "w");
331*4882a593Smuzhiyun         if (fp == NULL) {
332*4882a593Smuzhiyun             LOGE("Can't open %s\n", INTENT_FILE);
333*4882a593Smuzhiyun         } else {
334*4882a593Smuzhiyun             fputs(send_intent, fp);
335*4882a593Smuzhiyun             check_and_fclose(fp, INTENT_FILE);
336*4882a593Smuzhiyun         }
337*4882a593Smuzhiyun     }
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun     LOGI("finish_recovery Enter.....\n");
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun     // Copy logs to cache so the system can find out what happened.
342*4882a593Smuzhiyun     copy_log_file(LOG_FILE, true);
343*4882a593Smuzhiyun     copy_log_file(LAST_LOG_FILE, false);
344*4882a593Smuzhiyun     chmod(LAST_LOG_FILE, 0640);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun     // Reset to mormal system boot so recovery won't cycle indefinitely.
347*4882a593Smuzhiyun     struct bootloader_message boot;
348*4882a593Smuzhiyun     memset(&boot, 0, sizeof(boot));
349*4882a593Smuzhiyun     strlcpy(boot.systemFlag, systemFlag, sizeof(boot.systemFlag));
350*4882a593Smuzhiyun     set_bootloader_message(&boot);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun     // Remove the command file, so recovery won't repeat indefinitely.
353*4882a593Smuzhiyun     if (ensure_path_mounted(COMMAND_FILE) != 0 ||
354*4882a593Smuzhiyun         (unlink(COMMAND_FILE) && errno != ENOENT)) {
355*4882a593Smuzhiyun         LOGW("Can't unlink %s\n", COMMAND_FILE);
356*4882a593Smuzhiyun     }
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun     sync();  // For good measure.
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun static int
erase_volume(const char * volume)362*4882a593Smuzhiyun erase_volume(const char *volume)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun     ui_set_background(BACKGROUND_ICON_INSTALLING);
365*4882a593Smuzhiyun     ui_show_indeterminate_progress();
366*4882a593Smuzhiyun     ui_print("Formatting %s...\n", volume);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun     if (strcmp(volume, "/userdata") == 0) {
369*4882a593Smuzhiyun         // Any part of the log we'd copied to data is now gone.
370*4882a593Smuzhiyun         // Reset the pointer so we copy from the beginning of the temp
371*4882a593Smuzhiyun         // log.
372*4882a593Smuzhiyun         tmplog_offset = 0;
373*4882a593Smuzhiyun     }
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun     return format_volume(volume);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun static char*
copy_sideloaded_package(const char * original_path)379*4882a593Smuzhiyun copy_sideloaded_package(const char* original_path)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun     if (ensure_path_mounted(original_path) != 0) {
382*4882a593Smuzhiyun         LOGE("Can't mount %s\n", original_path);
383*4882a593Smuzhiyun         return NULL;
384*4882a593Smuzhiyun     }
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun     if (ensure_path_mounted(SIDELOAD_TEMP_DIR) != 0) {
387*4882a593Smuzhiyun         LOGE("Can't mount %s\n", SIDELOAD_TEMP_DIR);
388*4882a593Smuzhiyun         return NULL;
389*4882a593Smuzhiyun     }
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun     if (mkdir(SIDELOAD_TEMP_DIR, 0700) != 0) {
392*4882a593Smuzhiyun         if (errno != EEXIST) {
393*4882a593Smuzhiyun             LOGE("Can't mkdir %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno));
394*4882a593Smuzhiyun             return NULL;
395*4882a593Smuzhiyun         }
396*4882a593Smuzhiyun     }
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun     // verify that SIDELOAD_TEMP_DIR is exactly what we expect: a
399*4882a593Smuzhiyun     // directory, owned by root, readable and writable only by root.
400*4882a593Smuzhiyun     struct stat st;
401*4882a593Smuzhiyun     if (stat(SIDELOAD_TEMP_DIR, &st) != 0) {
402*4882a593Smuzhiyun         LOGE("failed to stat %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno));
403*4882a593Smuzhiyun         return NULL;
404*4882a593Smuzhiyun     }
405*4882a593Smuzhiyun     if (!S_ISDIR(st.st_mode)) {
406*4882a593Smuzhiyun         LOGE("%s isn't a directory\n", SIDELOAD_TEMP_DIR);
407*4882a593Smuzhiyun         return NULL;
408*4882a593Smuzhiyun     }
409*4882a593Smuzhiyun     if ((st.st_mode & 0777) != 0700) {
410*4882a593Smuzhiyun         LOGE("%s has perms %o\n", SIDELOAD_TEMP_DIR, st.st_mode);
411*4882a593Smuzhiyun         return NULL;
412*4882a593Smuzhiyun     }
413*4882a593Smuzhiyun     if (st.st_uid != 0) {
414*4882a593Smuzhiyun         LOGE("%s owned by %u; not root\n", SIDELOAD_TEMP_DIR, st.st_uid);
415*4882a593Smuzhiyun         return NULL;
416*4882a593Smuzhiyun     }
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun     char copy_path[PATH_MAX];
419*4882a593Smuzhiyun     strcpy(copy_path, SIDELOAD_TEMP_DIR);
420*4882a593Smuzhiyun     strcat(copy_path, "/package.zip");
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun     char* buffer = malloc(BUFSIZ);
423*4882a593Smuzhiyun     if (buffer == NULL) {
424*4882a593Smuzhiyun         LOGE("Failed to allocate buffer\n");
425*4882a593Smuzhiyun         return NULL;
426*4882a593Smuzhiyun     }
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun     size_t read;
429*4882a593Smuzhiyun     FILE* fin = fopen(original_path, "rb");
430*4882a593Smuzhiyun     if (fin == NULL) {
431*4882a593Smuzhiyun         LOGE("Failed to open %s (%s)\n", original_path, strerror(errno));
432*4882a593Smuzhiyun         return NULL;
433*4882a593Smuzhiyun     }
434*4882a593Smuzhiyun     FILE* fout = fopen(copy_path, "wb");
435*4882a593Smuzhiyun     if (fout == NULL) {
436*4882a593Smuzhiyun         LOGE("Failed to open %s (%s)\n", copy_path, strerror(errno));
437*4882a593Smuzhiyun         return NULL;
438*4882a593Smuzhiyun     }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun     while ((read = fread(buffer, 1, BUFSIZ, fin)) > 0) {
441*4882a593Smuzhiyun         if (fwrite(buffer, 1, read, fout) != read) {
442*4882a593Smuzhiyun             LOGE("Short write of %s (%s)\n", copy_path, strerror(errno));
443*4882a593Smuzhiyun             return NULL;
444*4882a593Smuzhiyun         }
445*4882a593Smuzhiyun     }
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun     free(buffer);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun     if (fclose(fout) != 0) {
450*4882a593Smuzhiyun         LOGE("Failed to close %s (%s)\n", copy_path, strerror(errno));
451*4882a593Smuzhiyun         return NULL;
452*4882a593Smuzhiyun     }
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun     if (fclose(fin) != 0) {
455*4882a593Smuzhiyun         LOGE("Failed to close %s (%s)\n", original_path, strerror(errno));
456*4882a593Smuzhiyun         return NULL;
457*4882a593Smuzhiyun     }
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun     // "adb push" is happy to overwrite read-only files when it's
460*4882a593Smuzhiyun     // running as root, but we'll try anyway.
461*4882a593Smuzhiyun     if (chmod(copy_path, 0400) != 0) {
462*4882a593Smuzhiyun         LOGE("Failed to chmod %s (%s)\n", copy_path, strerror(errno));
463*4882a593Smuzhiyun         return NULL;
464*4882a593Smuzhiyun     }
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun     return strdup(copy_path);
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun static char**
prepend_title(const char ** headers)470*4882a593Smuzhiyun prepend_title(const char** headers)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun     char* title[] = { "Linux system recovery <"
473*4882a593Smuzhiyun                       EXPAND(RECOVERY_API_VERSION) "e>",
474*4882a593Smuzhiyun                       "",
475*4882a593Smuzhiyun                       NULL
476*4882a593Smuzhiyun                     };
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun     // count the number of lines in our title, plus the
479*4882a593Smuzhiyun     // caller-provided headers.
480*4882a593Smuzhiyun     int count = 0;
481*4882a593Smuzhiyun     char** p;
482*4882a593Smuzhiyun     for (p = title; *p; ++p, ++count);
483*4882a593Smuzhiyun     for (p = (char** )headers; *p; ++p, ++count);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun     char** new_headers = malloc((count + 1) * sizeof(char*));
486*4882a593Smuzhiyun     char** h = new_headers;
487*4882a593Smuzhiyun     for (p = title; *p; ++p, ++h) *h = *p;
488*4882a593Smuzhiyun     for (p = (char** )headers; *p; ++p, ++h) *h = *p;
489*4882a593Smuzhiyun     *h = NULL;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun     return new_headers;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun static int
get_menu_selection(char ** headers,char ** items,int menu_only,int initial_selection)495*4882a593Smuzhiyun get_menu_selection(char** headers, char** items, int menu_only,
496*4882a593Smuzhiyun                    int initial_selection)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun     // throw away keys pressed previously, so user doesn't
499*4882a593Smuzhiyun     // accidentally trigger menu items.
500*4882a593Smuzhiyun     ui_clear_key_queue();
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun     ui_start_menu(headers, items, initial_selection);
503*4882a593Smuzhiyun     int selected = initial_selection;
504*4882a593Smuzhiyun     int chosen_item = -1;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun     while (chosen_item < 0) {
507*4882a593Smuzhiyun         int key = ui_wait_key();
508*4882a593Smuzhiyun         int visible = ui_text_visible();
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun         int action = device_handle_key(key, visible);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun         if (action < 0) {
513*4882a593Smuzhiyun             switch (action) {
514*4882a593Smuzhiyun             case HIGHLIGHT_UP:
515*4882a593Smuzhiyun                 --selected;
516*4882a593Smuzhiyun                 selected = ui_menu_select(selected);
517*4882a593Smuzhiyun                 break;
518*4882a593Smuzhiyun             case HIGHLIGHT_DOWN:
519*4882a593Smuzhiyun                 ++selected;
520*4882a593Smuzhiyun                 selected = ui_menu_select(selected);
521*4882a593Smuzhiyun                 break;
522*4882a593Smuzhiyun             case SELECT_ITEM:
523*4882a593Smuzhiyun                 chosen_item = selected;
524*4882a593Smuzhiyun                 break;
525*4882a593Smuzhiyun             case NO_ACTION:
526*4882a593Smuzhiyun                 break;
527*4882a593Smuzhiyun             }
528*4882a593Smuzhiyun         } else if (!menu_only) {
529*4882a593Smuzhiyun             chosen_item = action;
530*4882a593Smuzhiyun         }
531*4882a593Smuzhiyun     }
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun     ui_end_menu();
534*4882a593Smuzhiyun     return chosen_item;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun 
compare_string(const void * a,const void * b)537*4882a593Smuzhiyun static int compare_string(const void* a, const void* b)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun     return strcmp(*(const char**)a, *(const char**)b);
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun static int
sdcard_directory(const char * path)543*4882a593Smuzhiyun sdcard_directory(const char* path)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun     ensure_path_mounted(SDCARD_ROOT);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun     const char* MENU_HEADERS[] = { "Choose a package to install:",
548*4882a593Smuzhiyun                                    path,
549*4882a593Smuzhiyun                                    "",
550*4882a593Smuzhiyun                                    NULL
551*4882a593Smuzhiyun                                  };
552*4882a593Smuzhiyun     DIR* d;
553*4882a593Smuzhiyun     struct dirent* de;
554*4882a593Smuzhiyun     d = opendir(path);
555*4882a593Smuzhiyun     if (d == NULL) {
556*4882a593Smuzhiyun         LOGE("error opening %s: %s\n", path, strerror(errno));
557*4882a593Smuzhiyun         ensure_path_unmounted(SDCARD_ROOT);
558*4882a593Smuzhiyun         return 0;
559*4882a593Smuzhiyun     }
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun     char** headers = prepend_title(MENU_HEADERS);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun     int d_size = 0;
564*4882a593Smuzhiyun     int d_alloc = 10;
565*4882a593Smuzhiyun     char** dirs = malloc(d_alloc * sizeof(char*));
566*4882a593Smuzhiyun     int z_size = 1;
567*4882a593Smuzhiyun     int z_alloc = 10;
568*4882a593Smuzhiyun     char** zips = malloc(z_alloc * sizeof(char*));
569*4882a593Smuzhiyun     zips[0] = strdup("../");
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun     while ((de = readdir(d)) != NULL) {
572*4882a593Smuzhiyun         int name_len = strlen(de->d_name);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun         if (de->d_type == DT_DIR) {
575*4882a593Smuzhiyun             // skip "." and ".." entries
576*4882a593Smuzhiyun             if (name_len == 1 && de->d_name[0] == '.') continue;
577*4882a593Smuzhiyun             if (name_len == 2 && de->d_name[0] == '.' &&
578*4882a593Smuzhiyun                 de->d_name[1] == '.') continue;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun             if (d_size >= d_alloc) {
581*4882a593Smuzhiyun                 d_alloc *= 2;
582*4882a593Smuzhiyun                 dirs = realloc(dirs, d_alloc * sizeof(char*));
583*4882a593Smuzhiyun             }
584*4882a593Smuzhiyun             dirs[d_size] = malloc(name_len + 2);
585*4882a593Smuzhiyun             strcpy(dirs[d_size], de->d_name);
586*4882a593Smuzhiyun             dirs[d_size][name_len] = '/';
587*4882a593Smuzhiyun             dirs[d_size][name_len + 1] = '\0';
588*4882a593Smuzhiyun             ++d_size;
589*4882a593Smuzhiyun         } else if (de->d_type == DT_REG &&
590*4882a593Smuzhiyun                    name_len >= 4 &&
591*4882a593Smuzhiyun                    strncasecmp(de->d_name + (name_len - 4), ".zip", 4) == 0) {
592*4882a593Smuzhiyun             if (z_size >= z_alloc) {
593*4882a593Smuzhiyun                 z_alloc *= 2;
594*4882a593Smuzhiyun                 zips = realloc(zips, z_alloc * sizeof(char*));
595*4882a593Smuzhiyun             }
596*4882a593Smuzhiyun             zips[z_size++] = strdup(de->d_name);
597*4882a593Smuzhiyun         }
598*4882a593Smuzhiyun     }
599*4882a593Smuzhiyun     closedir(d);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun     qsort(dirs, d_size, sizeof(char*), compare_string);
602*4882a593Smuzhiyun     qsort(zips, z_size, sizeof(char*), compare_string);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun     // append dirs to the zips list
605*4882a593Smuzhiyun     if (d_size + z_size + 1 > z_alloc) {
606*4882a593Smuzhiyun         z_alloc = d_size + z_size + 1;
607*4882a593Smuzhiyun         zips = realloc(zips, z_alloc * sizeof(char*));
608*4882a593Smuzhiyun     }
609*4882a593Smuzhiyun     memcpy(zips + z_size, dirs, d_size * sizeof(char*));
610*4882a593Smuzhiyun     free(dirs);
611*4882a593Smuzhiyun     z_size += d_size;
612*4882a593Smuzhiyun     zips[z_size] = NULL;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun     int result;
615*4882a593Smuzhiyun     int chosen_item = 0;
616*4882a593Smuzhiyun     do {
617*4882a593Smuzhiyun         chosen_item = get_menu_selection(headers, zips, 1, chosen_item);
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun         char* item = zips[chosen_item];
620*4882a593Smuzhiyun         int item_len = strlen(item);
621*4882a593Smuzhiyun         if (chosen_item == 0) {          // item 0 is always "../"
622*4882a593Smuzhiyun             // go up but continue browsing (if the caller is sdcard_directory)
623*4882a593Smuzhiyun             result = -1;
624*4882a593Smuzhiyun             break;
625*4882a593Smuzhiyun         } else if (item[item_len - 1] == '/') {
626*4882a593Smuzhiyun             // recurse down into a subdirectory
627*4882a593Smuzhiyun             char new_path[PATH_MAX];
628*4882a593Smuzhiyun             strlcpy(new_path, path, PATH_MAX);
629*4882a593Smuzhiyun             strlcat(new_path, "/", PATH_MAX);
630*4882a593Smuzhiyun             strlcat(new_path, item, PATH_MAX);
631*4882a593Smuzhiyun             new_path[strlen(new_path) - 1] = '\0'; // truncate the trailing '/'
632*4882a593Smuzhiyun             result = sdcard_directory(new_path);
633*4882a593Smuzhiyun             if (result >= 0) break;
634*4882a593Smuzhiyun         } else {
635*4882a593Smuzhiyun             // selected a zip file:  attempt to install it, and return
636*4882a593Smuzhiyun             // the status to the caller.
637*4882a593Smuzhiyun             char new_path[PATH_MAX];
638*4882a593Smuzhiyun             strlcpy(new_path, path, PATH_MAX);
639*4882a593Smuzhiyun             strlcat(new_path, "/", PATH_MAX);
640*4882a593Smuzhiyun             strlcat(new_path, item, PATH_MAX);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun             ui_print("\n-- Install %s ...\n", path);
643*4882a593Smuzhiyun             set_sdcard_update_bootloader_message();
644*4882a593Smuzhiyun             char* copy = copy_sideloaded_package(new_path);
645*4882a593Smuzhiyun             ensure_path_unmounted(SDCARD_ROOT);
646*4882a593Smuzhiyun             if (copy) {
647*4882a593Smuzhiyun                 //result = install_package(copy);
648*4882a593Smuzhiyun                 free(copy);
649*4882a593Smuzhiyun             } else {
650*4882a593Smuzhiyun                 result = INSTALL_ERROR;
651*4882a593Smuzhiyun             }
652*4882a593Smuzhiyun             break;
653*4882a593Smuzhiyun         }
654*4882a593Smuzhiyun     } while (true);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun     int i;
657*4882a593Smuzhiyun     for (i = 0; i < z_size; ++i) free(zips[i]);
658*4882a593Smuzhiyun     free(zips);
659*4882a593Smuzhiyun     free(headers);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun     ensure_path_unmounted(SDCARD_ROOT);
662*4882a593Smuzhiyun     return result;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun static void
wipe_data(int confirm)666*4882a593Smuzhiyun wipe_data(int confirm)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun     if (confirm) {
669*4882a593Smuzhiyun         static char** title_headers = NULL;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun         if (title_headers == NULL) {
672*4882a593Smuzhiyun             char* headers[] = { "Confirm wipe of all user data?",
673*4882a593Smuzhiyun                                 "  THIS CAN NOT BE UNDONE.",
674*4882a593Smuzhiyun                                 "",
675*4882a593Smuzhiyun                                 NULL
676*4882a593Smuzhiyun                               };
677*4882a593Smuzhiyun             title_headers = prepend_title((const char**)headers);
678*4882a593Smuzhiyun         }
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun         char* items[] = { " No",
681*4882a593Smuzhiyun                           " No",
682*4882a593Smuzhiyun                           " No",
683*4882a593Smuzhiyun                           " No",
684*4882a593Smuzhiyun                           " No",
685*4882a593Smuzhiyun                           " No",
686*4882a593Smuzhiyun                           " No",
687*4882a593Smuzhiyun                           " Yes -- delete all user data",   // [7]
688*4882a593Smuzhiyun                           " No",
689*4882a593Smuzhiyun                           " No",
690*4882a593Smuzhiyun                           " No",
691*4882a593Smuzhiyun                           NULL
692*4882a593Smuzhiyun                         };
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun         int chosen_item = get_menu_selection(title_headers, items, 1, 0);
695*4882a593Smuzhiyun         if (chosen_item != 7) {
696*4882a593Smuzhiyun             return;
697*4882a593Smuzhiyun         }
698*4882a593Smuzhiyun     }
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun     ui_print("\n-- Wiping data...\n");
701*4882a593Smuzhiyun     device_wipe_data();
702*4882a593Smuzhiyun     erase_volume("/userdata");
703*4882a593Smuzhiyun     ui_print("Data wipe complete.\n");
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun 
ui_update(const char * fw_package)706*4882a593Smuzhiyun static int ui_update(const char * fw_package)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun     const char* binary = "/usr/bin/rkupdate";
709*4882a593Smuzhiyun     int i, ret = 0;
710*4882a593Smuzhiyun     int status = INSTALL_SUCCESS;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun     for (i = 0; i < 5; i++) {
713*4882a593Smuzhiyun         ret = ensure_path_mounted(fw_package);
714*4882a593Smuzhiyun         if (ret == 0)
715*4882a593Smuzhiyun             break;
716*4882a593Smuzhiyun         sleep(1);
717*4882a593Smuzhiyun         LOGD("mounted %s failed.\n", fw_package);
718*4882a593Smuzhiyun     }
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun     if (ret == 0 && access(fw_package, F_OK) == 0) {
721*4882a593Smuzhiyun         LOGD(">>>rkflash will update from %s\n", fw_package);
722*4882a593Smuzhiyun #ifdef USE_RKUPDATE
723*4882a593Smuzhiyun         status = do_rk_update(binary, fw_package);
724*4882a593Smuzhiyun #endif
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun #ifdef USE_UPDATEENGINE
727*4882a593Smuzhiyun         const char* updateEnginebin = "/usr/bin/updateEngine";
728*4882a593Smuzhiyun         status = do_rk_updateEngine(updateEnginebin, fw_package);
729*4882a593Smuzhiyun #endif
730*4882a593Smuzhiyun         if (status == INSTALL_SUCCESS) {
731*4882a593Smuzhiyun             strcpy(systemFlag, fw_package);
732*4882a593Smuzhiyun             /* update success, delete update.img */
733*4882a593Smuzhiyun             if (access(fw_package, F_OK) == 0)
734*4882a593Smuzhiyun                 remove(fw_package);
735*4882a593Smuzhiyun         }
736*4882a593Smuzhiyun     } else {
737*4882a593Smuzhiyun         status = INSTALL_ERROR;
738*4882a593Smuzhiyun     }
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun     if (status != INSTALL_SUCCESS) {
741*4882a593Smuzhiyun         ui_print("Installation aborted.\n");
742*4882a593Smuzhiyun         while (1) {
743*4882a593Smuzhiyun             /* code */
744*4882a593Smuzhiyun         }
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun         return -1;
747*4882a593Smuzhiyun     }
748*4882a593Smuzhiyun     ui_print("update.img Installation done.\n");
749*4882a593Smuzhiyun     ui_show_text(0);
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun     return 0;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun static void
prompt_and_wait()755*4882a593Smuzhiyun prompt_and_wait()
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun     char** headers = prepend_title((const char**)MENU_HEADERS);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun     for (;;) {
760*4882a593Smuzhiyun         finish_recovery(NULL);
761*4882a593Smuzhiyun         ui_reset_progress();
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun         int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0, 0);
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun         // device-specific code may take some action here.  It may
766*4882a593Smuzhiyun         // return one of the core actions handled in the switch
767*4882a593Smuzhiyun         // statement below.
768*4882a593Smuzhiyun         chosen_item = device_perform_action(chosen_item);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun         switch (chosen_item) {
771*4882a593Smuzhiyun         case ITEM_REBOOT:
772*4882a593Smuzhiyun             return;
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun         case ITEM_WIPE_DATA:
775*4882a593Smuzhiyun             wipe_data(ui_text_visible());
776*4882a593Smuzhiyun             if (!ui_text_visible()) return;
777*4882a593Smuzhiyun             break;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun         case ITEM_APPLY_SDCARD: {
780*4882a593Smuzhiyun             int status = sdcard_directory(SDCARD_ROOT);
781*4882a593Smuzhiyun             if (status >= 0) {
782*4882a593Smuzhiyun                 if (status != INSTALL_SUCCESS) {
783*4882a593Smuzhiyun                     ui_set_background(BACKGROUND_ICON_ERROR);
784*4882a593Smuzhiyun                     ui_print("Installation aborted.\n");
785*4882a593Smuzhiyun                 } else if (!ui_text_visible()) {
786*4882a593Smuzhiyun                     return;  // reboot if logs aren't visible
787*4882a593Smuzhiyun                 } else {
788*4882a593Smuzhiyun                     ui_print("\nInstall from sdcard complete.\n");
789*4882a593Smuzhiyun                 }
790*4882a593Smuzhiyun             }
791*4882a593Smuzhiyun         }
792*4882a593Smuzhiyun         break;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun         case ITEM_APPLY_USERDATA: {
795*4882a593Smuzhiyun             //update firmware from local userdata;
796*4882a593Smuzhiyun             const char* fw_package = "/userdata/update.img";
797*4882a593Smuzhiyun             // LOGD("%s:%d:-------->>>>> USERDATA update\n",__func__, __LINE__);
798*4882a593Smuzhiyun             int status = ui_update(fw_package);
799*4882a593Smuzhiyun             if (status < 0) {
800*4882a593Smuzhiyun                 ui_set_background(BACKGROUND_ICON_ERROR);
801*4882a593Smuzhiyun             } else if (!ui_text_visible()) {
802*4882a593Smuzhiyun                 return;  // reboot if logs aren't visible
803*4882a593Smuzhiyun             } else {
804*4882a593Smuzhiyun                 ui_print("\nInstall from sdcard complete.\n");
805*4882a593Smuzhiyun             }
806*4882a593Smuzhiyun         }
807*4882a593Smuzhiyun         break;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun         case ITEM_APPLY_UDISK: {
810*4882a593Smuzhiyun             //update firmware from udisk;
811*4882a593Smuzhiyun             const char* fw_package = "/udisk/update.img";
812*4882a593Smuzhiyun             // LOGD("%s:%d:-------->>>> UDISK update\n",__func__, __LINE__);
813*4882a593Smuzhiyun             int status = ui_update(fw_package);
814*4882a593Smuzhiyun             if (status < 0) {
815*4882a593Smuzhiyun                 ui_set_background(BACKGROUND_ICON_ERROR);
816*4882a593Smuzhiyun             } else if (!ui_text_visible()) {
817*4882a593Smuzhiyun                 ui_print("\nInstall from sdcard complete.\n");
818*4882a593Smuzhiyun                 return;  // reboot if logs aren't visible
819*4882a593Smuzhiyun             } else {
820*4882a593Smuzhiyun                 ui_print("\nInstall from sdcard complete.\n");
821*4882a593Smuzhiyun             }
822*4882a593Smuzhiyun         }
823*4882a593Smuzhiyun         break;
824*4882a593Smuzhiyun         }
825*4882a593Smuzhiyun     }
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun static void
print_property(const char * key,const char * name,void * cookie)829*4882a593Smuzhiyun print_property(const char *key, const char *name, void *cookie)
830*4882a593Smuzhiyun {
831*4882a593Smuzhiyun     printf("%s=%s\n", key, name);
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun int
main(int argc,char ** argv)836*4882a593Smuzhiyun main(int argc, char **argv)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun     bool bSDBoot    = false;
839*4882a593Smuzhiyun     bool bUDiskBoot = false;
840*4882a593Smuzhiyun     const char *sdupdate_package = NULL;
841*4882a593Smuzhiyun     const char *usbupdate_package = NULL;
842*4882a593Smuzhiyun     int previous_runs = 0;
843*4882a593Smuzhiyun     const char *send_intent = NULL;
844*4882a593Smuzhiyun     const char *update_package = NULL;
845*4882a593Smuzhiyun     const char *encrypted_fs_mode = NULL;
846*4882a593Smuzhiyun     int wipe_data = 0;
847*4882a593Smuzhiyun     int wipe_all = 0;
848*4882a593Smuzhiyun     int pcba_test = 0;  // add for pcba test
849*4882a593Smuzhiyun     int toggle_secure_fs = 0;
850*4882a593Smuzhiyun     int arg;
851*4882a593Smuzhiyun     bool isrkdebug = false;
852*4882a593Smuzhiyun     int log_level = LOG_DEBUG;
853*4882a593Smuzhiyun     encrypted_fs_info encrypted_fs_data;
854*4882a593Smuzhiyun     struct timeval start_time, end_time;
855*4882a593Smuzhiyun     long long elapsed_time;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun     gettimeofday(&start_time, NULL);
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun     get_args(&argc, &argv);
860*4882a593Smuzhiyun     strcpy(systemFlag, "false");
861*4882a593Smuzhiyun     while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
862*4882a593Smuzhiyun         switch (arg) {
863*4882a593Smuzhiyun         case 'p':
864*4882a593Smuzhiyun             previous_runs = atoi(optarg);
865*4882a593Smuzhiyun             break;
866*4882a593Smuzhiyun         case 's':
867*4882a593Smuzhiyun             send_intent = optarg;
868*4882a593Smuzhiyun             break;
869*4882a593Smuzhiyun         case 'u':
870*4882a593Smuzhiyun             update_package = optarg;
871*4882a593Smuzhiyun             break;
872*4882a593Smuzhiyun         case 'w':
873*4882a593Smuzhiyun             wipe_data = 1;
874*4882a593Smuzhiyun             break;
875*4882a593Smuzhiyun         case 'a':
876*4882a593Smuzhiyun             wipe_all = 1;
877*4882a593Smuzhiyun             break;
878*4882a593Smuzhiyun         case 'e':
879*4882a593Smuzhiyun             encrypted_fs_mode = optarg;
880*4882a593Smuzhiyun             toggle_secure_fs = 1;
881*4882a593Smuzhiyun             break;
882*4882a593Smuzhiyun         case 't':
883*4882a593Smuzhiyun             ui_show_text(1);
884*4882a593Smuzhiyun             break;
885*4882a593Smuzhiyun         case 'f':
886*4882a593Smuzhiyun             pcba_test = 1;
887*4882a593Smuzhiyun             break;  // add for pcba test
888*4882a593Smuzhiyun         case 'r':
889*4882a593Smuzhiyun             isrkdebug = true;
890*4882a593Smuzhiyun             break;
891*4882a593Smuzhiyun         case 'i':
892*4882a593Smuzhiyun             gr_set_rotate(atoi(optarg));
893*4882a593Smuzhiyun             break;
894*4882a593Smuzhiyun         case '?':
895*4882a593Smuzhiyun             LOGE("Invalid command argument\n");
896*4882a593Smuzhiyun             continue;
897*4882a593Smuzhiyun         }
898*4882a593Smuzhiyun     }
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun     time_t start = time(NULL);
901*4882a593Smuzhiyun     if ((access("/.rkdebug", F_OK) != 0) && (isrkdebug != true)) {
902*4882a593Smuzhiyun         // If these fail, there's not really anywhere to complain...
903*4882a593Smuzhiyun         if (freopen(TEMPORARY_LOG_FILE, "a", stdout) == NULL) {
904*4882a593Smuzhiyun             LOGW("freopen stdout error");
905*4882a593Smuzhiyun         }
906*4882a593Smuzhiyun         setbuf(stdout, NULL);
907*4882a593Smuzhiyun         if (freopen(TEMPORARY_LOG_FILE, "a", stderr) == NULL) {
908*4882a593Smuzhiyun             LOGE("freopen stderr error");
909*4882a593Smuzhiyun         }
910*4882a593Smuzhiyun         setbuf(stderr, NULL);
911*4882a593Smuzhiyun     }
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun     printf("\n");
914*4882a593Smuzhiyun     printf("*********************************************************\n");
915*4882a593Smuzhiyun     printf("            ROCKCHIP recovery system                     \n");
916*4882a593Smuzhiyun     printf("*********************************************************\n");
917*4882a593Smuzhiyun     printf("**** version : %s ****\n", recovery_version);
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun     LOGI("Starting recovery on %s\n", ctime(&start));
920*4882a593Smuzhiyun     while (access(coldboot_done, F_OK) != 0) {
921*4882a593Smuzhiyun         LOGI("coldboot not done, wait...\n");
922*4882a593Smuzhiyun         sleep(1);
923*4882a593Smuzhiyun     }
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun #ifndef RecoveryNoUi
926*4882a593Smuzhiyun     LOGI("Recovery System have UI defined.\n");
927*4882a593Smuzhiyun #endif
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun     ui_init();
930*4882a593Smuzhiyun     ui_set_background(BACKGROUND_ICON_INSTALLING);
931*4882a593Smuzhiyun     load_volume_table();
932*4882a593Smuzhiyun     setFlashPoint();
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun     bSDBoot = is_boot_from_SD();
935*4882a593Smuzhiyun     bUDiskBoot = is_boot_from_udisk();
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun     if (bSDBoot || bUDiskBoot) {
938*4882a593Smuzhiyun         char imageFile[64] = {0};
939*4882a593Smuzhiyun         if (bSDBoot) {
940*4882a593Smuzhiyun             if (is_sdcard_update()) {
941*4882a593Smuzhiyun                 strlcpy(imageFile, EX_SDCARD_ROOT, sizeof(imageFile));
942*4882a593Smuzhiyun                 strlcat(imageFile, "/sdupdate.img", sizeof(imageFile));
943*4882a593Smuzhiyun                 if (access(imageFile, F_OK) == 0) {
944*4882a593Smuzhiyun                     sdupdate_package = strdup(imageFile);
945*4882a593Smuzhiyun                     bSDBootUpdate = true;
946*4882a593Smuzhiyun                     ui_show_text(1);
947*4882a593Smuzhiyun                     LOGI("sdupdate_package = %s\n", sdupdate_package);
948*4882a593Smuzhiyun                 }
949*4882a593Smuzhiyun             }
950*4882a593Smuzhiyun         }
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun         if (bUDiskBoot) {
953*4882a593Smuzhiyun             if (is_udisk_update()) {
954*4882a593Smuzhiyun                 strlcpy(imageFile, EX_UDISK_ROOT, sizeof(imageFile));
955*4882a593Smuzhiyun                 strlcat(imageFile, "/sdupdate.img", sizeof(imageFile));
956*4882a593Smuzhiyun                 if (access(imageFile, F_OK) == 0) {
957*4882a593Smuzhiyun                     usbupdate_package = strdup(imageFile);
958*4882a593Smuzhiyun                     bUdiskUpdate = true;
959*4882a593Smuzhiyun                     ui_show_text(1);
960*4882a593Smuzhiyun                     LOGI("usbupdate_package = %s\n", usbupdate_package);
961*4882a593Smuzhiyun                 }
962*4882a593Smuzhiyun             }
963*4882a593Smuzhiyun         }
964*4882a593Smuzhiyun     }
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun     device_recovery_start();
967*4882a593Smuzhiyun 	system("echo default-on > /sys/class/leds/work/trigger");
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun     LOGI("Command:");
970*4882a593Smuzhiyun     for (arg = 0; arg < argc; arg++) {
971*4882a593Smuzhiyun         printf(" \"%s\"", argv[arg]);
972*4882a593Smuzhiyun     }
973*4882a593Smuzhiyun     printf("\n");
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun     if (update_package) {
976*4882a593Smuzhiyun         // For backwards compatibility on the cache partition only, if
977*4882a593Smuzhiyun         // we're given an old 'root' path "CACHE:foo", change it to
978*4882a593Smuzhiyun         // "/cache/foo".
979*4882a593Smuzhiyun         if (strncmp(update_package, "CACHE:", 6) == 0) {
980*4882a593Smuzhiyun             int len = strlen(update_package) + 10;
981*4882a593Smuzhiyun             char* modified_path = malloc(len);
982*4882a593Smuzhiyun             strlcpy(modified_path, "/cache/", len);
983*4882a593Smuzhiyun             strlcat(modified_path, update_package + 6, len);
984*4882a593Smuzhiyun             LOGI("(replacing path \"%s\" with \"%s\")\n",
985*4882a593Smuzhiyun                  update_package, modified_path);
986*4882a593Smuzhiyun             update_package = modified_path;
987*4882a593Smuzhiyun         }
988*4882a593Smuzhiyun     }
989*4882a593Smuzhiyun     printf("\n");
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun     int status = INSTALL_SUCCESS;
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun     if (toggle_secure_fs) {
994*4882a593Smuzhiyun         if (strcmp(encrypted_fs_mode, "on") == 0) {
995*4882a593Smuzhiyun             encrypted_fs_data.mode = MODE_ENCRYPTED_FS_ENABLED;
996*4882a593Smuzhiyun             ui_print("Enabling Encrypted FS.\n");
997*4882a593Smuzhiyun         } else if (strcmp(encrypted_fs_mode, "off") == 0) {
998*4882a593Smuzhiyun             encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED;
999*4882a593Smuzhiyun             ui_print("Disabling Encrypted FS.\n");
1000*4882a593Smuzhiyun         } else {
1001*4882a593Smuzhiyun             ui_print("Error: invalid Encrypted FS setting.\n");
1002*4882a593Smuzhiyun             status = INSTALL_ERROR;
1003*4882a593Smuzhiyun         }
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun         // Recovery strategy: if the data partition is damaged, disable encrypted file systems.
1006*4882a593Smuzhiyun         // This preventsthe device recycling endlessly in recovery mode.
1007*4882a593Smuzhiyun         if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) &&
1008*4882a593Smuzhiyun             (read_encrypted_fs_info(&encrypted_fs_data))) {
1009*4882a593Smuzhiyun             ui_print("Encrypted FS change aborted, resetting to disabled state.\n");
1010*4882a593Smuzhiyun             encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED;
1011*4882a593Smuzhiyun         }
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun         if (status != INSTALL_ERROR) {
1014*4882a593Smuzhiyun             if (erase_volume("/userdata")) {
1015*4882a593Smuzhiyun                 ui_print("Data wipe failed.\n");
1016*4882a593Smuzhiyun                 status = INSTALL_ERROR;
1017*4882a593Smuzhiyun #if 0
1018*4882a593Smuzhiyun             } else if (erase_volume("/cache")) {
1019*4882a593Smuzhiyun                 ui_print("Cache wipe failed.\n");
1020*4882a593Smuzhiyun                 status = INSTALL_ERROR;
1021*4882a593Smuzhiyun #endif
1022*4882a593Smuzhiyun             } else if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) &&
1023*4882a593Smuzhiyun                        (restore_encrypted_fs_info(&encrypted_fs_data))) {
1024*4882a593Smuzhiyun                 ui_print("Encrypted FS change aborted.\n");
1025*4882a593Smuzhiyun                 status = INSTALL_ERROR;
1026*4882a593Smuzhiyun             } else {
1027*4882a593Smuzhiyun                 ui_print("Successfully updated Encrypted FS.\n");
1028*4882a593Smuzhiyun                 status = INSTALL_SUCCESS;
1029*4882a593Smuzhiyun             }
1030*4882a593Smuzhiyun         }
1031*4882a593Smuzhiyun     } else if (update_package != NULL) {
1032*4882a593Smuzhiyun         int i, ret = 0;
1033*4882a593Smuzhiyun         const char* binary = "/usr/bin/rkupdate";
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun         rockchip_partition_check();
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun         for (i = 0; i < 5; i++) {
1038*4882a593Smuzhiyun             if (!ensure_path_mounted(update_package)) {
1039*4882a593Smuzhiyun                 LOGI("mounted %s Success.\n", update_package);
1040*4882a593Smuzhiyun                 break;
1041*4882a593Smuzhiyun             }
1042*4882a593Smuzhiyun             LOGW("mounted %s Failed. retry %d\n", update_package, i + 1);
1043*4882a593Smuzhiyun             sleep(1);
1044*4882a593Smuzhiyun         }
1045*4882a593Smuzhiyun         if (i != 5) {
1046*4882a593Smuzhiyun             LOGI(">>>rkflash will update from %s\n", update_package);
1047*4882a593Smuzhiyun #ifdef USE_RKUPDATE
1048*4882a593Smuzhiyun             status = do_rk_update(binary, update_package);
1049*4882a593Smuzhiyun #endif
1050*4882a593Smuzhiyun #ifdef USE_UPDATEENGINE
1051*4882a593Smuzhiyun             const char* updateEnginebin = "/usr/bin/updateEngine";
1052*4882a593Smuzhiyun             status = do_rk_updateEngine(updateEnginebin, update_package);
1053*4882a593Smuzhiyun #endif
1054*4882a593Smuzhiyun             if (status == INSTALL_SUCCESS) {
1055*4882a593Smuzhiyun                 strcpy(systemFlag, update_package);
1056*4882a593Smuzhiyun                 /* update success, delete update.img. */
1057*4882a593Smuzhiyun                 if (access(update_package, F_OK) == 0)
1058*4882a593Smuzhiyun                     remove(update_package);
1059*4882a593Smuzhiyun                 ui_print("update.img images success!\n");
1060*4882a593Smuzhiyun             } else {
1061*4882a593Smuzhiyun                 ui_print("update.img images failed!\n");
1062*4882a593Smuzhiyun             }
1063*4882a593Smuzhiyun         } else {
1064*4882a593Smuzhiyun             LOGE("mounted %s Failed.\n", update_package);
1065*4882a593Smuzhiyun             ui_print("mounted %s Failed.\n", update_package);
1066*4882a593Smuzhiyun         }
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun         if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
1069*4882a593Smuzhiyun         ui_print("update.img Installation done.\n");
1070*4882a593Smuzhiyun         //ui_show_text(0);
1071*4882a593Smuzhiyun     } else if (sdupdate_package != NULL) {
1072*4882a593Smuzhiyun         rockchip_partition_check();
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun         // update image from sdcard
1075*4882a593Smuzhiyun #ifdef USE_RKUPDATE
1076*4882a593Smuzhiyun         const char* binary = "/usr/bin/rkupdate";
1077*4882a593Smuzhiyun         LOGI(">>>sdboot update will update from %s\n", sdupdate_package);
1078*4882a593Smuzhiyun         status = do_rk_update(binary, sdupdate_package);
1079*4882a593Smuzhiyun #endif
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun #ifdef USE_UPDATEENGINE
1082*4882a593Smuzhiyun #undef FACTORY_FIRMWARE_IMAGE
1083*4882a593Smuzhiyun #undef CMD4RECOVERY_FILENAME
1084*4882a593Smuzhiyun #define FACTORY_FIRMWARE_IMAGE "/mnt/sdcard/out_image.img"
1085*4882a593Smuzhiyun #define CMD4RECOVERY_FILENAME "/mnt/sdcard/cmd4recovery"
1086*4882a593Smuzhiyun         if ((access(FACTORY_FIRMWARE_IMAGE, F_OK)) && access(CMD4RECOVERY_FILENAME, F_OK)) {
1087*4882a593Smuzhiyun             int tmp_fd = creat(CMD4RECOVERY_FILENAME, 0777);
1088*4882a593Smuzhiyun             if (tmp_fd < 0) {
1089*4882a593Smuzhiyun                 LOGE("creat %s error.\n", CMD4RECOVERY_FILENAME);
1090*4882a593Smuzhiyun                 status = INSTALL_ERROR;
1091*4882a593Smuzhiyun             } else {
1092*4882a593Smuzhiyun                 close(tmp_fd);
1093*4882a593Smuzhiyun                 const char* updateEnginebin = "/usr/bin/updateEngine";
1094*4882a593Smuzhiyun                 status = do_rk_updateEngine(updateEnginebin, sdupdate_package);
1095*4882a593Smuzhiyun             }
1096*4882a593Smuzhiyun         }
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun         if (isMtdDevice()) {
1099*4882a593Smuzhiyun             LOGI("start flash write to /dev/mtd0.\n");
1100*4882a593Smuzhiyun             size_t total_size;
1101*4882a593Smuzhiyun             size_t erase_size;
1102*4882a593Smuzhiyun             mtd_scan_partitions();
1103*4882a593Smuzhiyun             const MtdPartition *part = mtd_find_partition_by_name("rk-nand");
1104*4882a593Smuzhiyun             if ( part == NULL ) {
1105*4882a593Smuzhiyun                 part = mtd_find_partition_by_name("spi-nand0");
1106*4882a593Smuzhiyun             }
1107*4882a593Smuzhiyun             if (part == NULL || mtd_partition_info(part, &total_size, &erase_size, NULL)) {
1108*4882a593Smuzhiyun                 if ((!access(FACTORY_FIRMWARE_IMAGE, F_OK)) && mtd_find_partition_by_name("sfc_nor") != NULL) {
1109*4882a593Smuzhiyun                     LOGI("Info: start flash out_image.img to spi nor.\n");
1110*4882a593Smuzhiyun                     system("flashcp -v " FACTORY_FIRMWARE_IMAGE " /dev/mtd0");
1111*4882a593Smuzhiyun                 } else
1112*4882a593Smuzhiyun                     LOGE("Error: Can't find rk-nand or spi-nand0.\n");
1113*4882a593Smuzhiyun             } else {
1114*4882a593Smuzhiyun                 system("flash_erase /dev/mtd0 0x0 0");
1115*4882a593Smuzhiyun                 system("sh "CMD4RECOVERY_FILENAME);
1116*4882a593Smuzhiyun             }
1117*4882a593Smuzhiyun         } else {
1118*4882a593Smuzhiyun             LOGI("Start to dd data to emmc partition.\n");
1119*4882a593Smuzhiyun             system("sh "CMD4RECOVERY_FILENAME);
1120*4882a593Smuzhiyun             LOGI("sdcard upgrade done\n");
1121*4882a593Smuzhiyun         }
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun #endif
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun         if (status == INSTALL_SUCCESS) {
1126*4882a593Smuzhiyun             LOGI("update.img Installation success.\n");
1127*4882a593Smuzhiyun             ui_print("update.img Installation success.\n");
1128*4882a593Smuzhiyun             //ui_show_text(0);
1129*4882a593Smuzhiyun         }
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun     } else if (usbupdate_package != NULL) {
1132*4882a593Smuzhiyun         rockchip_partition_check();
1133*4882a593Smuzhiyun         // update image from udisk
1134*4882a593Smuzhiyun #ifdef USE_RKUPDATE
1135*4882a593Smuzhiyun         const char* binary = "/usr/bin/rkupdate";
1136*4882a593Smuzhiyun         LOGI(">>>sdboot update will update from %s\n", usbupdate_package);
1137*4882a593Smuzhiyun         status = do_rk_update(binary, usbupdate_package);
1138*4882a593Smuzhiyun #endif
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun #ifdef USE_UPDATEENGINE
1141*4882a593Smuzhiyun #undef FACTORY_FIRMWARE_IMAGE
1142*4882a593Smuzhiyun #undef CMD4RECOVERY_FILENAME
1143*4882a593Smuzhiyun #define FACTORY_FIRMWARE_IMAGE "/mnt/usb_storage/out_image.img"
1144*4882a593Smuzhiyun #define CMD4RECOVERY_FILENAME "/mnt/usb_storage/cmd4recovery"
1145*4882a593Smuzhiyun         if ((access(FACTORY_FIRMWARE_IMAGE, F_OK)) && access(CMD4RECOVERY_FILENAME, F_OK)) {
1146*4882a593Smuzhiyun             int tmp_fd = creat(CMD4RECOVERY_FILENAME, 0777);
1147*4882a593Smuzhiyun             if (tmp_fd < 0) {
1148*4882a593Smuzhiyun                 LOGE("creat %s error.\n", CMD4RECOVERY_FILENAME);
1149*4882a593Smuzhiyun                 status = INSTALL_ERROR;
1150*4882a593Smuzhiyun             } else {
1151*4882a593Smuzhiyun                 close(tmp_fd);
1152*4882a593Smuzhiyun                 const char* updateEnginebin = "/usr/bin/updateEngine";
1153*4882a593Smuzhiyun                 status = do_rk_updateEngine(updateEnginebin, usbupdate_package);
1154*4882a593Smuzhiyun             }
1155*4882a593Smuzhiyun         }
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun         if (isMtdDevice()) {
1158*4882a593Smuzhiyun             LOGI("start flash write to /dev/mtd0.\n");
1159*4882a593Smuzhiyun             size_t total_size;
1160*4882a593Smuzhiyun             size_t erase_size;
1161*4882a593Smuzhiyun             mtd_scan_partitions();
1162*4882a593Smuzhiyun             const MtdPartition *part = mtd_find_partition_by_name("rk-nand");
1163*4882a593Smuzhiyun             if ( part == NULL ) {
1164*4882a593Smuzhiyun                 part = mtd_find_partition_by_name("spi-nand0");
1165*4882a593Smuzhiyun             }
1166*4882a593Smuzhiyun             if (part == NULL || mtd_partition_info(part, &total_size, &erase_size, NULL)) {
1167*4882a593Smuzhiyun                 if ((!access(FACTORY_FIRMWARE_IMAGE, F_OK)) && mtd_find_partition_by_name("sfc_nor") != NULL) {
1168*4882a593Smuzhiyun                     LOGI("Info: start flash out_image.img to spi nor.\n");
1169*4882a593Smuzhiyun                     system("flashcp -v " FACTORY_FIRMWARE_IMAGE " /dev/mtd0");
1170*4882a593Smuzhiyun                 } else
1171*4882a593Smuzhiyun                     LOGE("Error: Can't find rk-nand or spi-nand0.\n");
1172*4882a593Smuzhiyun             } else {
1173*4882a593Smuzhiyun                 system("flash_erase /dev/mtd0 0x0 0");
1174*4882a593Smuzhiyun                 system("sh "CMD4RECOVERY_FILENAME);
1175*4882a593Smuzhiyun             }
1176*4882a593Smuzhiyun         } else {
1177*4882a593Smuzhiyun             LOGI("Start to dd data to emmc partition.\n");
1178*4882a593Smuzhiyun             system("sh "CMD4RECOVERY_FILENAME);
1179*4882a593Smuzhiyun             LOGI("usb upgrade done\n");
1180*4882a593Smuzhiyun         }
1181*4882a593Smuzhiyun #endif
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun         if (status == INSTALL_SUCCESS) {
1184*4882a593Smuzhiyun             LOGI("update.img Installation success.\n");
1185*4882a593Smuzhiyun             ui_print("update.img Installation success.\n");
1186*4882a593Smuzhiyun             //ui_show_text(0);
1187*4882a593Smuzhiyun         }
1188*4882a593Smuzhiyun     } else if (wipe_data) {
1189*4882a593Smuzhiyun         if (device_wipe_data()) status = INSTALL_ERROR;
1190*4882a593Smuzhiyun //        if (erase_volume("/userdata")) status = INSTALL_ERROR;
1191*4882a593Smuzhiyun         if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n");
1192*4882a593Smuzhiyun     } else if (wipe_all) {
1193*4882a593Smuzhiyun         if (device_wipe_data()) status = INSTALL_ERROR;
1194*4882a593Smuzhiyun //        if (erase_volume("/userdata")) status = INSTALL_ERROR;
1195*4882a593Smuzhiyun         if (status != INSTALL_SUCCESS) {
1196*4882a593Smuzhiyun             ui_print("Data wipe failed.\n");
1197*4882a593Smuzhiyun             LOGE("userdata wipe failed.\n");
1198*4882a593Smuzhiyun         } else {
1199*4882a593Smuzhiyun             ui_print("Data wipe done.\n");
1200*4882a593Smuzhiyun             LOGI("userdata wipe done.\n");
1201*4882a593Smuzhiyun         }
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun         //ui_show_text(0);
1204*4882a593Smuzhiyun     } else if (pcba_test) {
1205*4882a593Smuzhiyun         //pcba test todo...
1206*4882a593Smuzhiyun         printf("------------------ pcba test start -------------\n");
1207*4882a593Smuzhiyun         exit(EXIT_SUCCESS); //exit recovery bin directly, not start pcba here, in rkLanuch.sh
1208*4882a593Smuzhiyun         return 0;
1209*4882a593Smuzhiyun     } else {
1210*4882a593Smuzhiyun         if (argc == 1) { // No command specified
1211*4882a593Smuzhiyun             if (!bSDBootUpdate && !bUdiskUpdate && ui_text_visible())
1212*4882a593Smuzhiyun                 prompt_and_wait();
1213*4882a593Smuzhiyun             finish_recovery(NULL);
1214*4882a593Smuzhiyun             reboot(RB_AUTOBOOT);
1215*4882a593Smuzhiyun             return 0;
1216*4882a593Smuzhiyun         }
1217*4882a593Smuzhiyun         status = INSTALL_ERROR;  // No command specified
1218*4882a593Smuzhiyun     }
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun     if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
1221*4882a593Smuzhiyun     if (status != INSTALL_SUCCESS) {
1222*4882a593Smuzhiyun         LOGE("\n Install fail! \n");
1223*4882a593Smuzhiyun         if (!bSDBootUpdate && !bUdiskUpdate && ui_text_visible())
1224*4882a593Smuzhiyun             prompt_and_wait();
1225*4882a593Smuzhiyun     }
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun     if (sdupdate_package != NULL && bSDBootUpdate) {
1228*4882a593Smuzhiyun         if (status == INSTALL_SUCCESS) {
1229*4882a593Smuzhiyun             char *SDDdevice =
1230*4882a593Smuzhiyun                 strdup(get_mounted_device_from_path(EX_SDCARD_ROOT));
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun             ensure_ex_path_unmounted(EX_SDCARD_ROOT);
1233*4882a593Smuzhiyun             /* Updating is finished here, we must print this message
1234*4882a593Smuzhiyun              * in console, it shows user a specific message that
1235*4882a593Smuzhiyun              * updating is completely, remove SD CARD and reboot */
1236*4882a593Smuzhiyun             fflush(stdout);
1237*4882a593Smuzhiyun             freopen("/dev/console", "w", stdout);
1238*4882a593Smuzhiyun             LOGI("\nPlease remove SD CARD!!!, wait for reboot.\n");
1239*4882a593Smuzhiyun             ui_print("Please remove SD CARD!!!, wait for reboot.");
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 	    	if (access(SDDdevice, F_OK) == 0){
1242*4882a593Smuzhiyun                                system("echo heartbeat >  /sys/class/leds/work/trigger");
1243*4882a593Smuzhiyun             		 printf("{ \"PROGRAM\":\"OK\"} \n");
1244*4882a593Smuzhiyun 
1245*4882a593Smuzhiyun 		}
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun             while (access(SDDdevice, F_OK) == 0) { sleep(1); }
1248*4882a593Smuzhiyun             free(SDDdevice);
1249*4882a593Smuzhiyun         }
1250*4882a593Smuzhiyun     } else if (usbupdate_package && bUdiskUpdate) {
1251*4882a593Smuzhiyun         if (status == INSTALL_SUCCESS) {
1252*4882a593Smuzhiyun             char *udiskDev = strdup(get_mounted_device_from_path(EX_SDCARD_ROOT));
1253*4882a593Smuzhiyun             ensure_path_unmounted(EX_UDISK_ROOT);
1254*4882a593Smuzhiyun             /* Updating is finished here, we must print this message
1255*4882a593Smuzhiyun              * in console, it shows user a specific message that
1256*4882a593Smuzhiyun              * updating is completely, remove U-disk and reboot */
1257*4882a593Smuzhiyun             fflush(stdout);
1258*4882a593Smuzhiyun             freopen("/dev/console", "w", stdout);
1259*4882a593Smuzhiyun             LOGI("\nPlease remove U DISK!!!, wait for reboot.\n");
1260*4882a593Smuzhiyun             ui_print("Please remove U DISK!!!, wait for reboot.");
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun             while (access(udiskDev, F_OK) == 0) { sleep(1); }
1263*4882a593Smuzhiyun             free(udiskDev);
1264*4882a593Smuzhiyun         }
1265*4882a593Smuzhiyun     }
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun     // Otherwise, get ready to boot the main system...
1268*4882a593Smuzhiyun     finish_recovery(send_intent);
1269*4882a593Smuzhiyun     gettimeofday(&end_time, NULL);
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun     elapsed_time = (end_time.tv_sec - start_time.tv_sec) * 1000LL +
1272*4882a593Smuzhiyun                    (end_time.tv_usec - start_time.tv_usec) / 1000LL;
1273*4882a593Smuzhiyun     LOGI("recovery usage time:%lld ms\n", elapsed_time);
1274*4882a593Smuzhiyun     ui_print("Rebooting...\n");
1275*4882a593Smuzhiyun     LOGI("Reboot...\n");
1276*4882a593Smuzhiyun     ui_show_text(0);
1277*4882a593Smuzhiyun     fflush(stdout);
1278*4882a593Smuzhiyun     sync();
1279*4882a593Smuzhiyun     reboot(RB_AUTOBOOT);
1280*4882a593Smuzhiyun     return EXIT_SUCCESS;
1281*4882a593Smuzhiyun }
1282