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