blob: 8af70991584f16767426be8a331f557173b908b4 [file] [log] [blame]
Dees_Troy32c8eb82012-09-11 15:28:06 -04001
2#include <ctype.h>
3#include <errno.h>
4#include <fcntl.h>
5#include <limits.h>
6#include <sys/stat.h>
7#include <sys/wait.h>
8#include <unistd.h>
9
10#include <string.h>
11#include <stdio.h>
12
Dees_Troy2673cec2013-04-02 20:22:16 +000013#include "twcommon.h"
Dees_Troyb9d88ac2012-09-14 14:34:19 -040014#include "mincrypt/rsa.h"
15#include "mincrypt/sha.h"
Dees_Troy32c8eb82012-09-11 15:28:06 -040016#include "minui/minui.h"
17#include "minzip/SysUtil.h"
18#include "minzip/Zip.h"
19#include "mtdutils/mounts.h"
20#include "mtdutils/mtdutils.h"
Dees_Troy32c8eb82012-09-11 15:28:06 -040021#include "verifier.h"
Dees_Troy32c8eb82012-09-11 15:28:06 -040022#include "variables.h"
23#include "data.hpp"
24#include "partitions.hpp"
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -050025#include "twrpDigest.hpp"
Dees_Troy38bd7602012-09-14 13:33:53 -040026#include "twrp-functions.hpp"
Dees_Troy2673cec2013-04-02 20:22:16 +000027extern "C" {
28 #include "gui/gui.h"
29}
Dees_Troy32c8eb82012-09-11 15:28:06 -040030
Dees_Troy2673cec2013-04-02 20:22:16 +000031static int Run_Update_Binary(const char *path, ZipArchive *Zip, int* wipe_cache) {
32 const ZipEntry* binary_location = mzFindZipEntry(Zip, ASSUMED_UPDATE_BINARY_NAME);
33 string Temp_Binary = "/tmp/updater";
34 int binary_fd, ret_val, pipe_fd[2], status, zip_verify;
35 char buffer[1024];
36 const char** args = (const char**)malloc(sizeof(char*) * 5);
37 FILE* child_data;
Dees_Troy32c8eb82012-09-11 15:28:06 -040038
Dees_Troy2673cec2013-04-02 20:22:16 +000039 if (binary_location == NULL) {
40 mzCloseZipArchive(Zip);
41 return INSTALL_CORRUPT;
42 }
Dees_Troy32c8eb82012-09-11 15:28:06 -040043
Dees_Troy2673cec2013-04-02 20:22:16 +000044 // Delete any existing updater
45 if (TWFunc::Path_Exists(Temp_Binary) && unlink(Temp_Binary.c_str()) != 0) {
46 LOGINFO("Unable to unlink '%s'\n", Temp_Binary.c_str());
47 }
Dees_Troy32c8eb82012-09-11 15:28:06 -040048
Dees_Troy2673cec2013-04-02 20:22:16 +000049 binary_fd = creat(Temp_Binary.c_str(), 0755);
50 if (binary_fd < 0) {
51 mzCloseZipArchive(Zip);
52 LOGERR("Could not create file for updater extract in '%s'\n", Temp_Binary.c_str());
53 return INSTALL_ERROR;
54 }
Dees_Troy32c8eb82012-09-11 15:28:06 -040055
Dees_Troy2673cec2013-04-02 20:22:16 +000056 ret_val = mzExtractZipEntryToFile(Zip, binary_location, binary_fd);
57 close(binary_fd);
Dees_Troy32c8eb82012-09-11 15:28:06 -040058
Dees_Troy2673cec2013-04-02 20:22:16 +000059 if (!ret_val) {
Dees_Troy512376c2013-09-03 19:39:41 +000060 mzCloseZipArchive(Zip);
Dees_Troy2673cec2013-04-02 20:22:16 +000061 LOGERR("Could not extract '%s'\n", ASSUMED_UPDATE_BINARY_NAME);
62 return INSTALL_ERROR;
63 }
Dees_Troy32c8eb82012-09-11 15:28:06 -040064
Dees_Troy512376c2013-09-03 19:39:41 +000065 // If exists, extract file_contexts from the zip file
66 const ZipEntry* selinx_contexts = mzFindZipEntry(Zip, "file_contexts");
67 if (selinx_contexts == NULL) {
68 mzCloseZipArchive(Zip);
69 LOGINFO("Zip does not contain SELinux file_contexts file in its root.\n");
70 } else {
71 string output_filename = "/file_contexts";
72 LOGINFO("Zip contains SELinux file_contexts file in its root. Extracting to %s\n", output_filename.c_str());
73 // Delete any file_contexts
74 if (TWFunc::Path_Exists(output_filename) && unlink(output_filename.c_str()) != 0) {
75 LOGINFO("Unable to unlink '%s'\n", output_filename.c_str());
76 }
77
78 int file_contexts_fd = creat(output_filename.c_str(), 0644);
79 if (file_contexts_fd < 0) {
80 mzCloseZipArchive(Zip);
81 LOGERR("Could not extract file_contexts to '%s'\n", output_filename.c_str());
82 return INSTALL_ERROR;
83 }
84
85 ret_val = mzExtractZipEntryToFile(Zip, selinx_contexts, file_contexts_fd);
86 close(file_contexts_fd);
87
88 if (!ret_val) {
89 mzCloseZipArchive(Zip);
90 LOGERR("Could not extract '%s'\n", ASSUMED_UPDATE_BINARY_NAME);
91 return INSTALL_ERROR;
92 }
93 }
94 mzCloseZipArchive(Zip);
95
Dees_Troy2673cec2013-04-02 20:22:16 +000096 pipe(pipe_fd);
Dees_Troy32c8eb82012-09-11 15:28:06 -040097
Dees_Troy2673cec2013-04-02 20:22:16 +000098 args[0] = Temp_Binary.c_str();
99 args[1] = EXPAND(RECOVERY_API_VERSION);
100 char* temp = (char*)malloc(10);
101 sprintf(temp, "%d", pipe_fd[1]);
102 args[2] = temp;
103 args[3] = (char*)path;
104 args[4] = NULL;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400105
Dees_Troy2673cec2013-04-02 20:22:16 +0000106 pid_t pid = fork();
107 if (pid == 0) {
108 close(pipe_fd[0]);
109 execv(Temp_Binary.c_str(), (char* const*)args);
110 printf("E:Can't execute '%s'\n", Temp_Binary.c_str());
111 _exit(-1);
112 }
113 close(pipe_fd[1]);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400114
Dees_Troy2673cec2013-04-02 20:22:16 +0000115 *wipe_cache = 0;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400116
Dees_Troy2673cec2013-04-02 20:22:16 +0000117 DataManager::GetValue(TW_SIGNED_ZIP_VERIFY_VAR, zip_verify);
118 child_data = fdopen(pipe_fd[0], "r");
119 while (fgets(buffer, sizeof(buffer), child_data) != NULL) {
120 char* command = strtok(buffer, " \n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200121 if (command == NULL) {
122 continue;
123 } else if (strcmp(command, "progress") == 0) {
124 char* fraction_char = strtok(NULL, " \n");
125 char* seconds_char = strtok(NULL, " \n");
Dees_Troy32c8eb82012-09-11 15:28:06 -0400126
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200127 float fraction_float = strtof(fraction_char, NULL);
128 int seconds_float = strtol(seconds_char, NULL, 10);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400129
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200130 if (zip_verify)
Dees_Troy2673cec2013-04-02 20:22:16 +0000131 DataManager::ShowProgress(fraction_float * (1 - VERIFICATION_PROGRESS_FRACTION), seconds_float);
132 else
133 DataManager::ShowProgress(fraction_float, seconds_float);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200134 } else if (strcmp(command, "set_progress") == 0) {
135 char* fraction_char = strtok(NULL, " \n");
136 float fraction_float = strtof(fraction_char, NULL);
137 DataManager::SetProgress(fraction_float);
138 } else if (strcmp(command, "ui_print") == 0) {
139 char* display_value = strtok(NULL, "\n");
140 if (display_value) {
141 gui_print("%s", display_value);
142 } else {
143 gui_print("\n");
144 }
145 } else if (strcmp(command, "wipe_cache") == 0) {
146 *wipe_cache = 1;
147 } else if (strcmp(command, "clear_display") == 0) {
148 // Do nothing, not supported by TWRP
149 } else {
150 LOGERR("unknown command [%s]\n", command);
151 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000152 }
153 fclose(child_data);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400154
Dees_Troy2673cec2013-04-02 20:22:16 +0000155 waitpid(pid, &status, 0);
156 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
157 LOGERR("Error executing updater binary in zip '%s'\n", path);
158 return INSTALL_ERROR;
159 }
Dees_Troy32c8eb82012-09-11 15:28:06 -0400160
Dees_Troy2673cec2013-04-02 20:22:16 +0000161 return INSTALL_SUCCESS;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400162}
163
Dees_Troy32c8eb82012-09-11 15:28:06 -0400164extern "C" int TWinstall_zip(const char* path, int* wipe_cache) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000165 int ret_val, zip_verify, md5_return, key_count;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500166 twrpDigest md5sum;
167 string strpath = path;
Dees_Troy2673cec2013-04-02 20:22:16 +0000168 ZipArchive Zip;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400169
Dees_Troy2673cec2013-04-02 20:22:16 +0000170 gui_print("Installing '%s'...\nChecking for MD5 file...\n", path);
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500171 md5sum.setfn(strpath);
172 md5_return = md5sum.verify_md5digest();
173 if (md5_return == -2) {
Dees_Troy32c8eb82012-09-11 15:28:06 -0400174 // MD5 did not match.
Dees_Troy2673cec2013-04-02 20:22:16 +0000175 LOGERR("Zip MD5 does not match.\nUnable to install zip.\n");
Dees_Troy32c8eb82012-09-11 15:28:06 -0400176 return INSTALL_CORRUPT;
177 } else if (md5_return == -1) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000178 gui_print("Skipping MD5 check: no MD5 file found.\n");
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500179 } else if (md5_return == 0)
Dees_Troy2673cec2013-04-02 20:22:16 +0000180 gui_print("Zip MD5 matched.\n"); // MD5 found and matched.
Dees_Troy32c8eb82012-09-11 15:28:06 -0400181
182 DataManager::GetValue(TW_SIGNED_ZIP_VERIFY_VAR, zip_verify);
Dees_Troy2673cec2013-04-02 20:22:16 +0000183 DataManager::SetProgress(0);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400184 if (zip_verify) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000185 gui_print("Verifying zip signature...\n");
186 ret_val = verify_file(path);
187 if (ret_val != VERIFY_SUCCESS) {
188 LOGERR("Zip signature verification failed: %i\n", ret_val);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400189 return -1;
190 }
191 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000192 ret_val = mzOpenZipArchive(path, &Zip);
193 if (ret_val != 0) {
194 LOGERR("Zip file is corrupt!\n", path);
195 return INSTALL_CORRUPT;
196 }
197 return Run_Update_Binary(path, &Zip, wipe_cache);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400198}