blob: 518585940eab6f1d38bc324685dc59ae73478acf [file] [log] [blame]
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -08001#include <ctype.h>
2#include <errno.h>
3#include <fcntl.h>
4#include <getopt.h>
5#include <limits.h>
6#include <linux/input.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/reboot.h>
11#include <sys/types.h>
12#include <time.h>
13#include <unistd.h>
14
Koushik K. Duttae9234872010-02-12 00:43:24 -080015#include <sys/wait.h>
16#include <sys/limits.h>
17#include <dirent.h>
Koushik K. Dutta49f56892010-02-25 14:51:05 -080018#include <sys/stat.h>
Koushik K. Duttae9234872010-02-12 00:43:24 -080019
Koushik K. Dutta33370db2010-02-25 11:39:07 -080020#include <signal.h>
21#include <sys/wait.h>
22
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080023#include "bootloader.h"
24#include "common.h"
25#include "cutils/properties.h"
26#include "firmware.h"
27#include "install.h"
28#include "minui/minui.h"
29#include "minzip/DirUtil.h"
30#include "roots.h"
31#include "recovery_ui.h"
32
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -080033#include "commands.h"
34#include "amend/amend.h"
35
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080036int signature_check_enabled = 1;
37int script_assert_enabled = 1;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080038static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip";
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080039
40void
41toggle_signature_check()
42{
43 signature_check_enabled = !signature_check_enabled;
44 ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled");
45}
46
47void toggle_script_asserts()
48{
49 script_assert_enabled = !script_assert_enabled;
Koushik K. Duttae9234872010-02-12 00:43:24 -080050 ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled");
51}
52
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080053int install_zip(const char* packagefilepath)
Koushik K. Duttae9234872010-02-12 00:43:24 -080054{
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080055 ui_print("\n-- Installing: %s\n", packagefilepath);
56 set_sdcard_update_bootloader_message();
57 int status = install_package(packagefilepath);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080058 ui_reset_progress();
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080059 if (status != INSTALL_SUCCESS) {
60 ui_set_background(BACKGROUND_ICON_ERROR);
61 ui_print("Installation aborted.\n");
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080062 return 1;
Koushik K. Dutta79ce82c2010-02-25 12:03:17 -080063 }
64 if (firmware_update_pending()) {
65 ui_print("\nReboot via menu to complete\ninstallation.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080066 }
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080067 ui_set_background(BACKGROUND_ICON_NONE);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080068 ui_print("\nInstall from sdcard complete.\n");
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080069 return 0;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080070}
71
72char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip",
73 "choose zip from sdcard",
74 "toggle signature verification",
75 "toggle script asserts",
76 NULL };
77#define ITEM_APPLY_SDCARD 0
78#define ITEM_CHOOSE_ZIP 1
79#define ITEM_SIG_CHECK 2
80#define ITEM_ASSERTS 3
81
82void show_install_update_menu()
83{
84 static char* headers[] = { "Apply update from .zip file on SD card",
85 "",
86 NULL
87 };
88 for (;;)
89 {
90 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0);
91 switch (chosen_item)
92 {
93 case ITEM_ASSERTS:
94 toggle_script_asserts();
95 break;
96 case ITEM_SIG_CHECK:
97 toggle_signature_check();
98 break;
99 case ITEM_APPLY_SDCARD:
100 install_zip(SDCARD_PACKAGE_FILE);
101 break;
102 case ITEM_CHOOSE_ZIP:
103 show_choose_zip_menu();
104 break;
105 default:
106 return;
107 }
108
109 }
110}
111
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800112char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800113{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800114 char path[PATH_MAX] = "";
115 DIR *dir;
116 struct dirent *de;
117 int total = 0;
118 int i;
119 char** files;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800120 int pass;
121 *numFiles = 0;
122 int dirLen = strlen(directory);
Koushik K. Duttae9234872010-02-12 00:43:24 -0800123
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800124 dir = opendir(directory);
125 if (dir == NULL) {
126 ui_print("Couldn't open directory.\n");
127 return NULL;
128 }
129
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800130 int extension_length;
131 if (fileExtensionOrDirectory != NULL)
132 extension_length = strlen(fileExtensionOrDirectory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800133
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800134 int isCounting = 1;
135 i = 0;
136 for (pass = 0; pass < 2; pass++) {
137 while ((de=readdir(dir)) != NULL) {
138 // skip hidden files
139 if (de->d_name[0] == '.')
140 continue;
141
142 // NULL means that we are gathering directories, so skip this
143 if (fileExtensionOrDirectory != NULL)
144 {
145 // make sure that we can have the desired extension (prevent seg fault)
146 if (strlen(de->d_name) < extension_length)
147 continue;
148 // compare the extension
149 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
150 continue;
151 }
152 else
153 {
154 struct stat info;
155 char* fullFileName = (char*)malloc(strlen(de->d_name) + dirLen + 1);
156 strcpy(fullFileName, directory);
157 strcat(fullFileName, de->d_name);
158 stat(fullFileName, &info);
159 free(fullFileName);
160 // make sure it is a directory
161 if (!(S_ISDIR(info.st_mode)))
162 continue;
163 }
164
165 if (pass == 0)
166 {
167 total++;
168 continue;
169 }
170
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800171 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
172 strcpy(files[i], directory);
173 strcat(files[i], de->d_name);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800174 if (fileExtensionOrDirectory == NULL)
175 strcat(files[i], "/");
176 i++;
177 }
178 if (pass == 1)
179 break;
180 if (total == 0)
181 break;
182 rewinddir(dir);
183 *numFiles = total;
184 files = (char**) malloc((total+1)*sizeof(char*));
185 files[total]=NULL;
186 }
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800187
188 if(closedir(dir) < 0) {
189 LOGE("Failed to close directory.");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800190 }
191
192 if (total==0) {
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800193 return NULL;
194 }
195
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800196 return files;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800197}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800198
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800199void free_string_array(char** array)
200{
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800201 char* cursor = array[0];
202 int i = 0;
203 while (cursor != NULL)
204 {
205 free(cursor);
206 cursor = array[++i];
207 }
208 free(array);
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800209}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800210
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800211// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
212char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
213{
214 char path[PATH_MAX] = "";
215 DIR *dir;
216 struct dirent *de;
217 int numFiles = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800218 int numDirs = 0;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800219 int i;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800220
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800221 int dir_len = strlen(directory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800222
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800223 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
224 char** dirs;
225 if (fileExtensionOrDirectory != NULL)
226 dirs = gather_files(directory, NULL, &numDirs);
227 int total = numDirs + numFiles;
228 if (total == 0)
229 {
230 ui_print("No files found.\n");
231 return NULL;
232 }
233 char** list = (char**) malloc((total + 1) * sizeof(char*));
234 list[total] = NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800235
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800236
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800237 for (i = 0 ; i < numDirs; i++)
238 {
239 list[i] = strdup(dirs[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800240 }
241
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800242 for (i = 0 ; i < numFiles; i++)
243 {
244 list[numDirs + i] = strdup(files[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800245 }
246
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800247 for (;;)
248 {
249 int chosen_item = get_menu_selection(headers, list, 0);
250 if (chosen_item == GO_BACK)
251 break;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800252 if (chosen_item < numDirs)
253 {
254 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
255 if (subret != NULL)
256 return subret;
257 continue;
258 }
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800259 static char ret[PATH_MAX];
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800260 strcpy(ret, files[chosen_item - numDirs]);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800261 ui_print("File chosen: %s\n", ret);
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800262 return ret;
263 }
264 return NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800265}
266
267void show_choose_zip_menu()
268{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800269 if (ensure_root_path_mounted("SDCARD:") != 0) {
270 LOGE ("Can't mount /sdcard\n");
271 return;
272 }
273
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800274 static char* headers[] = { "Choose a zip to apply",
275 "",
276 NULL
277 };
278
279 char* file = choose_file_menu("/sdcard/", ".zip", headers);
280 if (file == NULL)
281 return;
282 char sdcard_package_file[1024];
283 strcpy(sdcard_package_file, "SDCARD:");
284 strcat(sdcard_package_file, file + strlen("/sdcard/"));
285 install_zip(sdcard_package_file);
286}
287
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800288// This was pulled from bionic: The default system command always looks
289// for shell in /system/bin/sh. This is bad.
290#define _PATH_BSHELL "/sbin/sh"
291#define system recovery_system
292extern char **environ;
293int
294system(const char *command)
295{
296 pid_t pid;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800297 sig_t intsave, quitsave;
298 sigset_t mask, omask;
299 int pstat;
300 char *argp[] = {"sh", "-c", NULL, NULL};
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800301
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800302 if (!command) /* just checking... */
303 return(1);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800304
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800305 argp[2] = (char *)command;
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800306
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800307 sigemptyset(&mask);
308 sigaddset(&mask, SIGCHLD);
309 sigprocmask(SIG_BLOCK, &mask, &omask);
310 switch (pid = vfork()) {
311 case -1: /* error */
312 sigprocmask(SIG_SETMASK, &omask, NULL);
313 return(-1);
314 case 0: /* child */
315 sigprocmask(SIG_SETMASK, &omask, NULL);
316 execve(_PATH_BSHELL, argp, environ);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800317 _exit(127);
318 }
319
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800320 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
321 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
322 pid = waitpid(pid, (int *)&pstat, 0);
323 sigprocmask(SIG_SETMASK, &omask, NULL);
324 (void)bsd_signal(SIGINT, intsave);
325 (void)bsd_signal(SIGQUIT, quitsave);
326 return (pid == -1 ? -1 : pstat);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800327}
328
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800329int do_nandroid_backup(char* backup_name)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800330{
Koushik K. Dutta60d7ee02010-03-07 22:16:55 -0800331 if (ensure_root_path_mounted("SDCARD:") != 0) {
332 LOGE ("Can't mount /sdcard\n");
333 return 1;
334 }
335
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800336 char cmd[PATH_MAX];
Koushik K. Dutta5306db52010-03-08 14:09:35 -0800337 if (NULL != backup_name)
Koushik K. Dutta8c866dc2010-03-08 14:20:37 -0800338 sprintf(cmd, "/sbin/nandroid-mobile.sh backup /sdcard/clockworkmod/backup/ %s", backup_name);
339 else
340 sprintf(cmd, "/sbin/nandroid-mobile.sh backup /sdcard/clockworkmod/backup/");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800341 ui_print("Performing backup...\n");
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800342 int ret = system(cmd);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800343 if (ret != 0)
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800344 {
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800345 ui_print("Error while backing up! Error code: %d\n", ret);
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800346 return ret;
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800347 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800348 ui_print("Backup complete.\n");
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800349 return ret;
350}
351
352int do_nandroid_restore(char* backup_path)
353{
Koushik K. Dutta60d7ee02010-03-07 22:16:55 -0800354 if (ensure_root_path_mounted("SDCARD:") != 0) {
355 LOGE ("Can't mount /sdcard\n");
356 return 1;
357 }
358
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800359 char* command[PATH_MAX];
360 sprintf(command, "nandroid-mobile.sh restore %s", backup_path);
361 ui_print("Performing restore...\n");
362 int ret = system(command);
363 if (ret != 0)
364 {
365 ui_print("Error while restoring!\n");
366 return ret;
367 }
368 ui_print("Restore complete.\n");
369 return ret;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800370}
371
372void show_nandroid_restore_menu()
373{
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800374 static char* headers[] = { "Choose an image to restore",
375 "",
376 NULL
377 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800378
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800379 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800380 if (file == NULL)
381 return;
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800382 do_nandroid_restore(file);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800383}
384
385void do_mount_usb_storage()
386{
387 system("echo /dev/block/mmcblk0 > /sys/devices/platform/usb_mass_storage/lun0/file");
388 static char* headers[] = { "USB Mass Storage device",
389 "Leaving this menu unmount",
390 "your SD card from your PC.",
391 "",
392 NULL
393 };
394
395 static char* list[] = { "Unmount", NULL };
396
397 for (;;)
398 {
399 int chosen_item = get_menu_selection(headers, list, 0);
400 if (chosen_item == GO_BACK || chosen_item == 0)
401 break;
402 }
403
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800404 system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
Koushik K. Dutta03173782010-02-26 14:14:23 -0800405 system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800406}
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800407
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800408#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
409
410int extendedcommand_file_exists()
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800411{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800412 struct stat file_info;
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800413 return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
414}
415
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800416int run_script_from_buffer(char* script_data, int script_len, char* filename)
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800417{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800418 /* Parse the script. Note that the script and parse tree are never freed.
419 */
420 const AmCommandList *commands = parseAmendScript(script_data, script_len);
421 if (commands == NULL) {
422 printf("Syntax error in update script\n");
423 return 1;
424 } else {
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800425 printf("Parsed %.*s\n", script_len, filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800426 }
427
428 /* Execute the script.
429 */
430 int ret = execCommandList((ExecContext *)1, commands);
431 if (ret != 0) {
432 int num = ret;
433 char *line, *next = script_data;
434 while (next != NULL && ret-- > 0) {
435 line = next;
436 next = memchr(line, '\n', script_data + script_len - line);
437 if (next != NULL) *next++ = '\0';
438 }
439 printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
440 return 1;
441 }
442
443 return 0;
444}
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800445
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800446int run_script(char* filename, int delete_file)
447{
448 struct stat file_info;
449 if (0 != stat(filename, &file_info)) {
450 printf("Error executing stat on file: %s\n", filename);
451 return 1;
452 }
453
454 int script_len = file_info.st_size;
455 char* script_data = (char*)malloc(script_len);
456 FILE *file = fopen(filename, "rb");
457 fread(script_data, script_len, 1, file);
458 fclose(file);
459 if (delete_file)
460 remove(filename);
461
462 return run_script_from_buffer(script_data, script_len, filename);
463}
464
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800465int run_and_remove_extendedcommand()
466{
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800467 int i = 0;
468 for (i = 20; i > 0; i--) {
469 ui_print("Waiting for SD Card to mount (%ds)\n", i);
470 if (ensure_root_path_mounted("SDCARD:") == 0) {
471 ui_print("SD Card mounted...\n");
472 break;
473 }
474 sleep(1);
475 }
476 if (i == 0) {
477 ui_print("Timed out waiting for SD card... continuing anyways.");
478 }
479
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800480 return run_script(EXTENDEDCOMMAND_SCRIPT, 1);
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800481}
482
483int amend_main(int argc, char** argv)
484{
485 if (argc != 2)
486 {
487 printf("Usage: amend <script>\n");
488 return 0;
489 }
490
491 RecoveryCommandContext ctx = { NULL };
492 if (register_update_commands(&ctx)) {
493 LOGE("Can't install update commands\n");
494 }
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800495 return run_script(argv[1], 0);
Koushik K. Dutta5306db52010-03-08 14:09:35 -0800496}