blob: 28d0ba58e32b12fd8ed25b60c600abd48ee4bd3a [file] [log] [blame]
Dees_Troy38bd7602012-09-14 13:33:53 -04001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/stat.h>
5#include <sys/vfs.h>
6#include <unistd.h>
7#include <vector>
8#include <dirent.h>
9#include <time.h>
Dees_Troy43d8b002012-09-17 16:00:01 -040010#include <errno.h>
Dees_Troya58bead2012-09-27 09:49:29 -040011#include <sys/reboot.h>
Dees_Troy38bd7602012-09-14 13:33:53 -040012
13#include "twrp-functions.hpp"
14#include "partitions.hpp"
15#include "common.h"
Dees_Troyb46a6842012-09-25 11:06:46 -040016#include "data.hpp"
Dees_Troya58bead2012-09-27 09:49:29 -040017#include "bootloader.h"
Dees_Troy38bd7602012-09-14 13:33:53 -040018
19/* Checks md5 for a path
20 Return values:
21 -1 : MD5 does not exist
22 0 : Failed
23 1 : Success */
24int TWFunc::Check_MD5(string File) {
25 int ret;
26 string Command, DirPath, MD5_File, Sline, Filename, MD5_File_Filename, OK;
27 char line[255];
28 size_t pos;
29
30 MD5_File = File + ".md5";
Dees_Troy2a923582012-09-20 12:13:34 -040031 if (Path_Exists(MD5_File)) {
Dees_Troy38bd7602012-09-14 13:33:53 -040032 DirPath = Get_Path(File);
Dees_Troy38bd7602012-09-14 13:33:53 -040033 MD5_File = Get_Filename(MD5_File);
Dees_Troy2a923582012-09-20 12:13:34 -040034 Command = "cd '" + DirPath + "' && /sbin/busybox md5sum -c '" + MD5_File + "' > /tmp/md5output";
Dees_Troy8170a922012-09-18 15:40:25 -040035 system(Command.c_str());
Dees_Troy38bd7602012-09-14 13:33:53 -040036 FILE * cs = fopen("/tmp/md5output", "r");
37 if (cs == NULL) {
38 LOGE("Unable to open md5 output file.\n");
39 return 0;
40 }
41
42 fgets(line, sizeof(line), cs);
Dees_Troy2a923582012-09-20 12:13:34 -040043 fclose(cs);
Dees_Troy38bd7602012-09-14 13:33:53 -040044
45 Sline = line;
46 pos = Sline.find(":");
47 if (pos != string::npos) {
48 Filename = Get_Filename(File);
49 MD5_File_Filename = Sline.substr(0, pos);
50 OK = Sline.substr(pos + 2, Sline.size() - pos - 2);
51 if (Filename == MD5_File_Filename && (OK == "OK" || OK == "OK\n")) {
52 //MD5 is good, return 1
53 ret = 1;
54 } else {
55 // MD5 is bad, return 0
56 ret = 0;
57 }
58 } else {
59 // MD5 is bad, return 0
60 ret = 0;
61 }
Dees_Troy38bd7602012-09-14 13:33:53 -040062 } else {
63 //No md5 file, return -1
64 ret = -1;
65 }
66
67 return ret;
68}
69
70// Returns "file.name" from a full /path/to/file.name
71string TWFunc::Get_Filename(string Path) {
72 size_t pos = Path.find_last_of("/");
73 if (pos != string::npos) {
74 string Filename;
75 Filename = Path.substr(pos + 1, Path.size() - pos - 1);
76 return Filename;
77 } else
78 return Path;
79}
80
81// Returns "/path/to/" from a full /path/to/file.name
82string TWFunc::Get_Path(string Path) {
83 size_t pos = Path.find_last_of("/");
84 if (pos != string::npos) {
85 string Pathonly;
86 Pathonly = Path.substr(0, pos + 1);
87 return Pathonly;
88 } else
89 return Path;
90}
91
92// Returns "/path" from a full /path/to/file.name
93string TWFunc::Get_Root_Path(string Path) {
94 string Local_Path = Path;
95
96 // Make sure that we have a leading slash
97 if (Local_Path.substr(0, 1) != "/")
98 Local_Path = "/" + Local_Path;
99
100 // Trim the path to get the root path only
101 size_t position = Local_Path.find("/", 2);
102 if (position != string::npos) {
103 Local_Path.resize(position);
104 }
105 return Local_Path;
106}
107
108void TWFunc::install_htc_dumlock(void) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400109 int need_libs = 0;
110
111 if (!PartitionManager.Mount_By_Path("/system", true))
112 return;
113
114 if (!PartitionManager.Mount_By_Path("/data", true))
115 return;
116
117 ui_print("Installing HTC Dumlock to system...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400118 system("cp /res/htcd/htcdumlocksys /system/bin/htcdumlock && chmod 755 /system/bin/htcdumlock");
119 if (!Path_Exists("/system/bin/flash_image")) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400120 ui_print("Installing flash_image...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400121 system("cp /res/htcd/flash_imagesys /system/bin/flash_image && chmod 755 /system/bin/flash_image");
Dees_Troy38bd7602012-09-14 13:33:53 -0400122 need_libs = 1;
123 } else
124 ui_print("flash_image is already installed, skipping...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400125 if (!Path_Exists("/system/bin/dump_image")) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400126 ui_print("Installing dump_image...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400127 system("cp /res/htcd/dump_imagesys /system/bin/dump_image && chmod 755 /system/bin/dump_image");
Dees_Troy38bd7602012-09-14 13:33:53 -0400128 need_libs = 1;
129 } else
130 ui_print("dump_image is already installed, skipping...\n");
131 if (need_libs) {
132 ui_print("Installing libs needed for flash_image and dump_image...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400133 system("cp /res/htcd/libbmlutils.so /system/lib && chmod 755 /system/lib/libbmlutils.so");
134 system("cp /res/htcd/libflashutils.so /system/lib && chmod 755 /system/lib/libflashutils.so");
135 system("cp /res/htcd/libmmcutils.so /system/lib && chmod 755 /system/lib/libmmcutils.so");
136 system("cp /res/htcd/libmtdutils.so /system/lib && chmod 755 /system/lib/libmtdutils.so");
Dees_Troy38bd7602012-09-14 13:33:53 -0400137 }
138 ui_print("Installing HTC Dumlock app...\n");
139 mkdir("/data/app", 0777);
Dees_Troy8170a922012-09-18 15:40:25 -0400140 system("rm /data/app/com.teamwin.htcdumlock*");
141 system("cp /res/htcd/HTCDumlock.apk /data/app/com.teamwin.htcdumlock.apk");
Dees_Troy38bd7602012-09-14 13:33:53 -0400142 sync();
143 ui_print("HTC Dumlock is installed.\n");
144}
145
146void TWFunc::htc_dumlock_restore_original_boot(void) {
147 if (!PartitionManager.Mount_By_Path("/sdcard", true))
148 return;
149
150 ui_print("Restoring original boot...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400151 system("htcdumlock restore");
Dees_Troy38bd7602012-09-14 13:33:53 -0400152 ui_print("Original boot restored.\n");
153}
154
155void TWFunc::htc_dumlock_reflash_recovery_to_boot(void) {
156 if (!PartitionManager.Mount_By_Path("/sdcard", true))
157 return;
158
159 ui_print("Reflashing recovery to boot...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400160 system("htcdumlock recovery noreboot");
Dees_Troy38bd7602012-09-14 13:33:53 -0400161 ui_print("Recovery is flashed to boot.\n");
162}
Dees_Troy43d8b002012-09-17 16:00:01 -0400163
164int TWFunc::Recursive_Mkdir(string Path) {
165 string pathCpy = Path;
166 string wholePath;
167 size_t pos = pathCpy.find("/", 2);
168
169 while (pos != string::npos)
170 {
171 wholePath = pathCpy.substr(0, pos);
172 if (mkdir(wholePath.c_str(), 0777) && errno != EEXIST) {
173 LOGE("Unable to create folder: %s (errno=%d)\n", wholePath.c_str(), errno);
174 return false;
175 }
176
177 pos = pathCpy.find("/", pos + 1);
178 }
179 if (mkdir(wholePath.c_str(), 0777) && errno != EEXIST)
180 return false;
181 return true;
182}
183
184unsigned long long TWFunc::Get_Folder_Size(string Path, bool Display_Error) {
185 DIR* d;
186 struct dirent* de;
187 struct stat st;
188 char path2[1024], filename[1024];
189 unsigned long long dusize = 0;
190
191 // Make a copy of path in case the data in the pointer gets overwritten later
192 strcpy(path2, Path.c_str());
193
194 d = opendir(path2);
195 if (d == NULL)
196 {
197 LOGE("error opening '%s'\n", path2);
198 return 0;
199 }
200
201 while ((de = readdir(d)) != NULL)
202 {
203 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
204 {
205 strcpy(filename, path2);
206 strcat(filename, "/");
207 strcat(filename, de->d_name);
208 dusize += Get_Folder_Size(filename, Display_Error);
209 }
210 else if (de->d_type == DT_REG)
211 {
212 strcpy(filename, path2);
213 strcat(filename, "/");
214 strcat(filename, de->d_name);
215 stat(filename, &st);
216 dusize += (unsigned long long)(st.st_size);
217 }
218 }
219 closedir(d);
220
221 return dusize;
222}
223
224bool TWFunc::Path_Exists(string Path) {
225 // Check to see if the Path exists
Dees_Troy7c2dec82012-09-26 09:49:14 -0400226 struct stat st;
Dees_Troy43d8b002012-09-17 16:00:01 -0400227
Dees_Troy7c2dec82012-09-26 09:49:14 -0400228 if (stat(Path.c_str(), &st) != 0)
Dees_Troy43d8b002012-09-17 16:00:01 -0400229 return false;
230 else
231 return true;
Dees_Troyb46a6842012-09-25 11:06:46 -0400232}
233
234void TWFunc::GUI_Operation_Text(string Read_Value, string Default_Text) {
235 string Display_Text;
236
237 DataManager::GetValue(Read_Value, Display_Text);
238 if (Display_Text.empty())
239 Display_Text = Default_Text;
240
241 DataManager::SetValue("tw_operation", Display_Text);
242 DataManager::SetValue("tw_partition", "");
243}
244
245void TWFunc::GUI_Operation_Text(string Read_Value, string Partition_Name, string Default_Text) {
246 string Display_Text;
247
248 DataManager::GetValue(Read_Value, Display_Text);
249 if (Display_Text.empty())
250 Display_Text = Default_Text;
251
252 DataManager::SetValue("tw_operation", Display_Text);
253 DataManager::SetValue("tw_partition", Partition_Name);
Dees_Troy7c2dec82012-09-26 09:49:14 -0400254}
255
256unsigned long TWFunc::Get_File_Size(string Path) {
257 struct stat st;
258
259 if (stat(Path.c_str(), &st) != 0)
260 return 0;
261 return st.st_size;
Dees_Troya58bead2012-09-27 09:49:29 -0400262}
263
264static const char *COMMAND_FILE = "/cache/recovery/command";
265static const char *INTENT_FILE = "/cache/recovery/intent";
266static const char *LOG_FILE = "/cache/recovery/log";
267static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
268static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
269static const char *CACHE_ROOT = "/cache";
270static const char *SDCARD_ROOT = "/sdcard";
271static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
272static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
273
274// close a file, log an error if the error indicator is set
275void TWFunc::check_and_fclose(FILE *fp, const char *name) {
276 fflush(fp);
277 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
278 fclose(fp);
279}
280
281void TWFunc::copy_log_file(const char* source, const char* destination, int append) {
282 FILE *log = fopen_path(destination, append ? "a" : "w");
283 if (log == NULL) {
284 LOGE("Can't open %s\n", destination);
285 } else {
286 FILE *tmplog = fopen(source, "r");
287 if (tmplog != NULL) {
288 if (append) {
289 fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write
290 }
291 char buf[4096];
292 while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log);
293 if (append) {
294 tmplog_offset = ftell(tmplog);
295 }
296 check_and_fclose(tmplog, source);
297 }
298 check_and_fclose(log, destination);
299 }
300}
301
302// clear the recovery command and prepare to boot a (hopefully working) system,
303// copy our log file to cache as well (for the system to read), and
304// record any intent we were asked to communicate back to the system.
305// this function is idempotent: call it as many times as you like.
306void TWFunc::twfinish_recovery(const char *send_intent) {
307 // By this point, we're ready to return to the main system...
308 if (send_intent != NULL) {
309 FILE *fp = fopen_path(INTENT_FILE, "w");
310 if (fp == NULL) {
311 LOGE("Can't open %s\n", INTENT_FILE);
312 } else {
313 fputs(send_intent, fp);
314 check_and_fclose(fp, INTENT_FILE);
315 }
316 }
317
318 // Copy logs to cache so the system can find out what happened.
319 copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
320 copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
321 copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
322 chmod(LOG_FILE, 0600);
323 chown(LOG_FILE, 1000, 1000); // system user
324 chmod(LAST_LOG_FILE, 0640);
325 chmod(LAST_INSTALL_FILE, 0644);
326
327 // Reset to normal system boot so recovery won't cycle indefinitely.
328 struct bootloader_message boot;
329 memset(&boot, 0, sizeof(boot));
330 set_bootloader_message(&boot);
331
332 // Remove the command file, so recovery won't repeat indefinitely.
333 if (system("mount /cache") != 0 ||
334 (unlink(COMMAND_FILE) && errno != ENOENT)) {
335 LOGW("Can't unlink %s\n", COMMAND_FILE);
336 }
337
338 system("umount /cache");
339 sync(); // For good measure.
340}
341
342// reboot: Reboot the system. Return -1 on error, no return on success
343int TWFunc::tw_reboot(RebootCommand command)
344{
345 // Always force a sync before we reboot
346 sync();
347
348 switch (command)
349 {
350 case rb_current:
351 case rb_system:
352 twfinish_recovery("s");
353 sync();
354 check_and_run_script("/sbin/rebootsystem.sh", "reboot system");
355 return reboot(RB_AUTOBOOT);
356 case rb_recovery:
357 check_and_run_script("/sbin/rebootrecovery.sh", "reboot recovery");
358 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "recovery");
359 case rb_bootloader:
360 check_and_run_script("/sbin/rebootbootloader.sh", "reboot bootloader");
361 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "bootloader");
362 case rb_poweroff:
363 check_and_run_script("/sbin/poweroff.sh", "power off");
364 return reboot(RB_POWER_OFF);
365 case rb_download:
366 check_and_run_script("/sbin/rebootdownload.sh", "reboot download");
367 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "download");
368 return 1;
369 default:
370 return -1;
371 }
372 return -1;
373}
374
375void TWFunc::check_and_run_script(const char* script_file, const char* display_name)
376{
377 // Check for and run startup script if script exists
378 struct stat st;
379 if (stat(script_file, &st) == 0) {
380 ui_print("Running %s script...\n", display_name);
381 char command[255];
382 strcpy(command, "chmod 755 ");
383 strcat(command, script_file);
384 system(command);
385 system(script_file);
386 ui_print("\nFinished running %s script.\n", display_name);
387 }
Dees_Troy43d8b002012-09-17 16:00:01 -0400388}