blob: e7ffb8f80e13abc87987adb529719e1ec34feb2e [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];
337 if (NULL == backup_name)
338 backup_name = "";
339 sprintf(cmd, "/sbin/nandroid-mobile.sh backup /sdcard/clockworkmod/backup/ %s", backup_name);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800340 ui_print("Performing backup...\n");
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800341 int ret = system(cmd);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800342 if (ret != 0)
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800343 {
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800344 ui_print("Error while backing up! Error code: %d\n", ret);
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800345 return ret;
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800346 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800347 ui_print("Backup complete.\n");
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800348 return ret;
349}
350
351int do_nandroid_restore(char* backup_path)
352{
Koushik K. Dutta60d7ee02010-03-07 22:16:55 -0800353 if (ensure_root_path_mounted("SDCARD:") != 0) {
354 LOGE ("Can't mount /sdcard\n");
355 return 1;
356 }
357
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800358 char* command[PATH_MAX];
359 sprintf(command, "nandroid-mobile.sh restore %s", backup_path);
360 ui_print("Performing restore...\n");
361 int ret = system(command);
362 if (ret != 0)
363 {
364 ui_print("Error while restoring!\n");
365 return ret;
366 }
367 ui_print("Restore complete.\n");
368 return ret;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800369}
370
371void show_nandroid_restore_menu()
372{
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800373 static char* headers[] = { "Choose an image to restore",
374 "",
375 NULL
376 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800377
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800378 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800379 if (file == NULL)
380 return;
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800381 do_nandroid_restore(file);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800382}
383
384void do_mount_usb_storage()
385{
386 system("echo /dev/block/mmcblk0 > /sys/devices/platform/usb_mass_storage/lun0/file");
387 static char* headers[] = { "USB Mass Storage device",
388 "Leaving this menu unmount",
389 "your SD card from your PC.",
390 "",
391 NULL
392 };
393
394 static char* list[] = { "Unmount", NULL };
395
396 for (;;)
397 {
398 int chosen_item = get_menu_selection(headers, list, 0);
399 if (chosen_item == GO_BACK || chosen_item == 0)
400 break;
401 }
402
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800403 system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
Koushik K. Dutta03173782010-02-26 14:14:23 -0800404 system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800405}
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800406
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800407#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
408
409int extendedcommand_file_exists()
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800410{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800411 struct stat file_info;
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800412 return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
413}
414
415int run_script(char* filename)
416{
417 struct stat file_info;
418 if (0 != stat(filename, &file_info)) {
419 printf("Error executing stat on file: %s\n", filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800420 return 1;
421 }
422
423 int script_len = file_info.st_size;
424 char* script_data = (char*)malloc(script_len);
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800425 FILE *file = fopen(filename, "rb");
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800426 fread(script_data, script_len, 1, file);
427 fclose(file);
428
429 /* Parse the script. Note that the script and parse tree are never freed.
430 */
431 const AmCommandList *commands = parseAmendScript(script_data, script_len);
432 if (commands == NULL) {
433 printf("Syntax error in update script\n");
434 return 1;
435 } else {
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800436 printf("Parsed %.*s\n", script_len, filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800437 }
438
439 /* Execute the script.
440 */
441 int ret = execCommandList((ExecContext *)1, commands);
442 if (ret != 0) {
443 int num = ret;
444 char *line, *next = script_data;
445 while (next != NULL && ret-- > 0) {
446 line = next;
447 next = memchr(line, '\n', script_data + script_len - line);
448 if (next != NULL) *next++ = '\0';
449 }
450 printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
451 return 1;
452 }
453
454 return 0;
455}
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800456
457int run_and_remove_extendedcommand()
458{
459 int ret = run_script(EXTENDEDCOMMAND_SCRIPT);
460 remove(EXTENDEDCOMMAND_SCRIPT);
461 return ret;
462}
463
464int amend_main(int argc, char** argv)
465{
466 if (argc != 2)
467 {
468 printf("Usage: amend <script>\n");
469 return 0;
470 }
471
472 RecoveryCommandContext ctx = { NULL };
473 if (register_update_commands(&ctx)) {
474 LOGE("Can't install update commands\n");
475 }
Koushik K. Duttaa9483082010-03-07 21:47:41 -0800476 return run_script(argv[1]);
477}