blob: e9fd1a7c66289f5263d98789a094b49291758ac8 [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. Duttabcdd0032010-02-21 21:10:25 -080053void 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. Dutta001c5b52010-02-25 14:53:57 -080062 return;
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. Duttabcdd0032010-02-21 21:10:25 -080069}
70
71char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip",
72 "choose zip from sdcard",
73 "toggle signature verification",
74 "toggle script asserts",
75 NULL };
76#define ITEM_APPLY_SDCARD 0
77#define ITEM_CHOOSE_ZIP 1
78#define ITEM_SIG_CHECK 2
79#define ITEM_ASSERTS 3
80
81void show_install_update_menu()
82{
83 static char* headers[] = { "Apply update from .zip file on SD card",
84 "",
85 NULL
86 };
87 for (;;)
88 {
89 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0);
90 switch (chosen_item)
91 {
92 case ITEM_ASSERTS:
93 toggle_script_asserts();
94 break;
95 case ITEM_SIG_CHECK:
96 toggle_signature_check();
97 break;
98 case ITEM_APPLY_SDCARD:
99 install_zip(SDCARD_PACKAGE_FILE);
100 break;
101 case ITEM_CHOOSE_ZIP:
102 show_choose_zip_menu();
103 break;
104 default:
105 return;
106 }
107
108 }
109}
110
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800111char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800112{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800113 char path[PATH_MAX] = "";
114 DIR *dir;
115 struct dirent *de;
116 int total = 0;
117 int i;
118 char** files;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800119 int pass;
120 *numFiles = 0;
121 int dirLen = strlen(directory);
Koushik K. Duttae9234872010-02-12 00:43:24 -0800122
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800123 dir = opendir(directory);
124 if (dir == NULL) {
125 ui_print("Couldn't open directory.\n");
126 return NULL;
127 }
128
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800129 int extension_length;
130 if (fileExtensionOrDirectory != NULL)
131 extension_length = strlen(fileExtensionOrDirectory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800132
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800133 int isCounting = 1;
134 i = 0;
135 for (pass = 0; pass < 2; pass++) {
136 while ((de=readdir(dir)) != NULL) {
137 // skip hidden files
138 if (de->d_name[0] == '.')
139 continue;
140
141 // NULL means that we are gathering directories, so skip this
142 if (fileExtensionOrDirectory != NULL)
143 {
144 // make sure that we can have the desired extension (prevent seg fault)
145 if (strlen(de->d_name) < extension_length)
146 continue;
147 // compare the extension
148 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
149 continue;
150 }
151 else
152 {
153 struct stat info;
154 char* fullFileName = (char*)malloc(strlen(de->d_name) + dirLen + 1);
155 strcpy(fullFileName, directory);
156 strcat(fullFileName, de->d_name);
157 stat(fullFileName, &info);
158 free(fullFileName);
159 // make sure it is a directory
160 if (!(S_ISDIR(info.st_mode)))
161 continue;
162 }
163
164 if (pass == 0)
165 {
166 total++;
167 continue;
168 }
169
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800170 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
171 strcpy(files[i], directory);
172 strcat(files[i], de->d_name);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800173 if (fileExtensionOrDirectory == NULL)
174 strcat(files[i], "/");
175 i++;
176 }
177 if (pass == 1)
178 break;
179 if (total == 0)
180 break;
181 rewinddir(dir);
182 *numFiles = total;
183 files = (char**) malloc((total+1)*sizeof(char*));
184 files[total]=NULL;
185 }
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800186
187 if(closedir(dir) < 0) {
188 LOGE("Failed to close directory.");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800189 }
190
191 if (total==0) {
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800192 return NULL;
193 }
194
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800195 return files;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800196}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800197
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800198void free_string_array(char** array)
199{
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800200 char* cursor = array[0];
201 int i = 0;
202 while (cursor != NULL)
203 {
204 free(cursor);
205 cursor = array[++i];
206 }
207 free(array);
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800208}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800209
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800210// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
211char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
212{
213 char path[PATH_MAX] = "";
214 DIR *dir;
215 struct dirent *de;
216 int numFiles = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800217 int numDirs = 0;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800218 int i;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800219
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800220 int dir_len = strlen(directory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800221
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800222 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
223 char** dirs;
224 if (fileExtensionOrDirectory != NULL)
225 dirs = gather_files(directory, NULL, &numDirs);
226 int total = numDirs + numFiles;
227 if (total == 0)
228 {
229 ui_print("No files found.\n");
230 return NULL;
231 }
232 char** list = (char**) malloc((total + 1) * sizeof(char*));
233 list[total] = NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800234
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800235
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800236 for (i = 0 ; i < numDirs; i++)
237 {
238 list[i] = strdup(dirs[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800239 }
240
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800241 for (i = 0 ; i < numFiles; i++)
242 {
243 list[numDirs + i] = strdup(files[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800244 }
245
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800246 for (;;)
247 {
248 int chosen_item = get_menu_selection(headers, list, 0);
249 if (chosen_item == GO_BACK)
250 break;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800251 if (chosen_item < numDirs)
252 {
253 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
254 if (subret != NULL)
255 return subret;
256 continue;
257 }
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800258 static char ret[PATH_MAX];
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800259 strcpy(ret, files[chosen_item - numDirs]);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800260 ui_print("File chosen: %s\n", ret);
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800261 return ret;
262 }
263 return NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800264}
265
266void show_choose_zip_menu()
267{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800268 if (ensure_root_path_mounted("SDCARD:") != 0) {
269 LOGE ("Can't mount /sdcard\n");
270 return;
271 }
272
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800273 static char* headers[] = { "Choose a zip to apply",
274 "",
275 NULL
276 };
277
278 char* file = choose_file_menu("/sdcard/", ".zip", headers);
279 if (file == NULL)
280 return;
281 char sdcard_package_file[1024];
282 strcpy(sdcard_package_file, "SDCARD:");
283 strcat(sdcard_package_file, file + strlen("/sdcard/"));
284 install_zip(sdcard_package_file);
285}
286
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800287// This was pulled from bionic: The default system command always looks
288// for shell in /system/bin/sh. This is bad.
289#define _PATH_BSHELL "/sbin/sh"
290#define system recovery_system
291extern char **environ;
292int
293system(const char *command)
294{
295 pid_t pid;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800296 sig_t intsave, quitsave;
297 sigset_t mask, omask;
298 int pstat;
299 char *argp[] = {"sh", "-c", NULL, NULL};
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800300
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800301 if (!command) /* just checking... */
302 return(1);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800303
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800304 argp[2] = (char *)command;
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800305
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800306 sigemptyset(&mask);
307 sigaddset(&mask, SIGCHLD);
308 sigprocmask(SIG_BLOCK, &mask, &omask);
309 switch (pid = vfork()) {
310 case -1: /* error */
311 sigprocmask(SIG_SETMASK, &omask, NULL);
312 return(-1);
313 case 0: /* child */
314 sigprocmask(SIG_SETMASK, &omask, NULL);
315 execve(_PATH_BSHELL, argp, environ);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800316 _exit(127);
317 }
318
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800319 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
320 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
321 pid = waitpid(pid, (int *)&pstat, 0);
322 sigprocmask(SIG_SETMASK, &omask, NULL);
323 (void)bsd_signal(SIGINT, intsave);
324 (void)bsd_signal(SIGQUIT, quitsave);
325 return (pid == -1 ? -1 : pstat);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800326}
327
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800328int do_nandroid_backup(char* backup_name)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800329{
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800330 char cmd[PATH_MAX];
331 if (NULL == backup_name)
332 backup_name = "";
333 sprintf(cmd, "/sbin/nandroid-mobile.sh backup /sdcard/clockworkmod/backup/ %s", backup_name);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800334 ui_print("Performing backup...\n");
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800335 int ret = system(cmd);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800336 if (ret != 0)
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800337 {
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800338 ui_print("Error while backing up! Error code: %d\n", ret);
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800339 return ret;
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800340 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800341 ui_print("Backup complete.\n");
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800342 return ret;
343}
344
345int do_nandroid_restore(char* backup_path)
346{
347 char* command[PATH_MAX];
348 sprintf(command, "nandroid-mobile.sh restore %s", backup_path);
349 ui_print("Performing restore...\n");
350 int ret = system(command);
351 if (ret != 0)
352 {
353 ui_print("Error while restoring!\n");
354 return ret;
355 }
356 ui_print("Restore complete.\n");
357 return ret;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800358}
359
360void show_nandroid_restore_menu()
361{
362 if (ensure_root_path_mounted("SDCARD:") != 0) {
363 LOGE ("Can't mount /sdcard\n");
Koushik K. Duttae9234872010-02-12 00:43:24 -0800364 return;
365 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800366
367 static char* headers[] = { "Choose an image to restore",
368 "",
369 NULL
370 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800371
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800372 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800373 if (file == NULL)
374 return;
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800375 do_nandroid_restore(file);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800376}
377
378void do_mount_usb_storage()
379{
380 system("echo /dev/block/mmcblk0 > /sys/devices/platform/usb_mass_storage/lun0/file");
381 static char* headers[] = { "USB Mass Storage device",
382 "Leaving this menu unmount",
383 "your SD card from your PC.",
384 "",
385 NULL
386 };
387
388 static char* list[] = { "Unmount", NULL };
389
390 for (;;)
391 {
392 int chosen_item = get_menu_selection(headers, list, 0);
393 if (chosen_item == GO_BACK || chosen_item == 0)
394 break;
395 }
396
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800397 system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
Koushik K. Dutta03173782010-02-26 14:14:23 -0800398 system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800399}
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800400
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800401#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
402
403int extendedcommand_file_exists()
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800404{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800405 struct stat file_info;
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800406 return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
407}
408
409int run_script(char* filename)
410{
411 struct stat file_info;
412 if (0 != stat(filename, &file_info)) {
413 printf("Error executing stat on file: %s\n", filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800414 return 1;
415 }
416
417 int script_len = file_info.st_size;
418 char* script_data = (char*)malloc(script_len);
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800419 FILE *file = fopen(filename, "rb");
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800420 fread(script_data, script_len, 1, file);
421 fclose(file);
422
423 /* Parse the script. Note that the script and parse tree are never freed.
424 */
425 const AmCommandList *commands = parseAmendScript(script_data, script_len);
426 if (commands == NULL) {
427 printf("Syntax error in update script\n");
428 return 1;
429 } else {
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800430 printf("Parsed %.*s\n", script_len, filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800431 }
432
433 /* Execute the script.
434 */
435 int ret = execCommandList((ExecContext *)1, commands);
436 if (ret != 0) {
437 int num = ret;
438 char *line, *next = script_data;
439 while (next != NULL && ret-- > 0) {
440 line = next;
441 next = memchr(line, '\n', script_data + script_len - line);
442 if (next != NULL) *next++ = '\0';
443 }
444 printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
445 return 1;
446 }
447
448 return 0;
449}
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800450
451int run_and_remove_extendedcommand()
452{
453 int ret = run_script(EXTENDEDCOMMAND_SCRIPT);
454 remove(EXTENDEDCOMMAND_SCRIPT);
455 return ret;
456}
457
458int amend_main(int argc, char** argv)
459{
460 if (argc != 2)
461 {
462 printf("Usage: amend <script>\n");
463 return 0;
464 }
465
466 RecoveryCommandContext ctx = { NULL };
467 if (register_update_commands(&ctx)) {
468 LOGE("Can't install update commands\n");
469 }
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800470 return run_script(argv[1]);
471}