blob: 420982452550add040f955c01a7d0d7534319de2 [file] [log] [blame]
Dees Troy3be70a82013-10-22 14:25:12 +00001/*
2 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
18
Dees_Troy38bd7602012-09-14 13:33:53 -040019#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
Dees_Troy38bd7602012-09-14 13:33:53 -040022#include <unistd.h>
23#include <vector>
24#include <dirent.h>
25#include <time.h>
Dees_Troy43d8b002012-09-17 16:00:01 -040026#include <errno.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050027#include <fcntl.h>
28#include <sys/mount.h>
Dees_Troya58bead2012-09-27 09:49:29 -040029#include <sys/reboot.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050030#include <sys/sendfile.h>
31#include <sys/stat.h>
32#include <sys/vfs.h>
Dees_Troy83bd4832013-05-04 12:39:56 +000033#include <sys/types.h>
34#include <sys/wait.h>
Dees_Troya4438782013-02-22 18:44:00 +000035#ifdef ANDROID_RB_POWEROFF
36 #include "cutils/android_reboot.h"
37#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050038#include <iostream>
39#include <fstream>
Dees_Troy83bd4832013-05-04 12:39:56 +000040#include <sstream>
Dees_Troy38bd7602012-09-14 13:33:53 -040041#include "twrp-functions.hpp"
42#include "partitions.hpp"
Dees_Troy2673cec2013-04-02 20:22:16 +000043#include "twcommon.h"
Dees_Troyb46a6842012-09-25 11:06:46 -040044#include "data.hpp"
Dees_Troy3477d712012-09-27 15:44:01 -040045#include "variables.h"
Dees_Troy2673cec2013-04-02 20:22:16 +000046#include "bootloader.h"
Dees_Troy83bd4832013-05-04 12:39:56 +000047#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
48 #include "openaes/inc/oaes_lib.h"
49#endif
Dees_Troy38bd7602012-09-14 13:33:53 -040050
Dees_Troyb05ddee2013-01-28 20:24:50 +000051extern "C" {
52 #include "libcrecovery/common.h"
53}
54
bigbiff bigbiff9c754052013-01-09 09:09:08 -050055/* Execute a command */
Vojtech Bocek05534202013-09-11 08:11:56 +020056int TWFunc::Exec_Cmd(const string& cmd, string &result) {
Dees_Troy29a06352013-08-24 12:06:47 +000057 FILE* exec;
58 char buffer[130];
59 int ret = 0;
60 exec = __popen(cmd.c_str(), "r");
61 if (!exec) return -1;
62 while(!feof(exec)) {
63 memset(&buffer, 0, sizeof(buffer));
64 if (fgets(buffer, 128, exec) != NULL) {
65 buffer[128] = '\n';
66 buffer[129] = NULL;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050067 result += buffer;
Dees_Troyb05ddee2013-01-28 20:24:50 +000068 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -050069 }
Dees_Troy29a06352013-08-24 12:06:47 +000070 ret = __pclose(exec);
71 return ret;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050072}
73
Vojtech Bocek05534202013-09-11 08:11:56 +020074int TWFunc::Exec_Cmd(const string& cmd) {
75 pid_t pid;
76 int status;
77 switch(pid = fork())
78 {
79 case -1:
80 LOGERR("Exec_Cmd(): vfork failed!\n");
81 return -1;
82 case 0: // child
83 execl("/sbin/sh", "sh", "-c", cmd.c_str(), NULL);
84 _exit(127);
85 break;
86 default:
87 {
88 if (TWFunc::Wait_For_Child(pid, &status, cmd) != 0)
89 return -1;
90 else
91 return 0;
92 }
93 }
94}
95
Dees_Troy38bd7602012-09-14 13:33:53 -040096// Returns "file.name" from a full /path/to/file.name
97string TWFunc::Get_Filename(string Path) {
98 size_t pos = Path.find_last_of("/");
99 if (pos != string::npos) {
100 string Filename;
101 Filename = Path.substr(pos + 1, Path.size() - pos - 1);
102 return Filename;
103 } else
104 return Path;
105}
106
107// Returns "/path/to/" from a full /path/to/file.name
108string TWFunc::Get_Path(string Path) {
109 size_t pos = Path.find_last_of("/");
110 if (pos != string::npos) {
111 string Pathonly;
112 Pathonly = Path.substr(0, pos + 1);
113 return Pathonly;
114 } else
115 return Path;
116}
117
118// Returns "/path" from a full /path/to/file.name
119string TWFunc::Get_Root_Path(string Path) {
120 string Local_Path = Path;
121
122 // Make sure that we have a leading slash
123 if (Local_Path.substr(0, 1) != "/")
124 Local_Path = "/" + Local_Path;
125
126 // Trim the path to get the root path only
127 size_t position = Local_Path.find("/", 2);
128 if (position != string::npos) {
129 Local_Path.resize(position);
130 }
131 return Local_Path;
132}
133
134void TWFunc::install_htc_dumlock(void) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400135 int need_libs = 0;
136
137 if (!PartitionManager.Mount_By_Path("/system", true))
138 return;
139
140 if (!PartitionManager.Mount_By_Path("/data", true))
141 return;
142
Dees_Troy2673cec2013-04-02 20:22:16 +0000143 gui_print("Installing HTC Dumlock to system...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500144 copy_file("/res/htcd/htcdumlocksys", "/system/bin/htcdumlock", 0755);
Dees_Troy8170a922012-09-18 15:40:25 -0400145 if (!Path_Exists("/system/bin/flash_image")) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000146 gui_print("Installing flash_image...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500147 copy_file("/res/htcd/flash_imagesys", "/system/bin/flash_image", 0755);
Dees_Troy38bd7602012-09-14 13:33:53 -0400148 need_libs = 1;
149 } else
Dees_Troy2673cec2013-04-02 20:22:16 +0000150 gui_print("flash_image is already installed, skipping...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400151 if (!Path_Exists("/system/bin/dump_image")) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000152 gui_print("Installing dump_image...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500153 copy_file("/res/htcd/dump_imagesys", "/system/bin/dump_image", 0755);
Dees_Troy38bd7602012-09-14 13:33:53 -0400154 need_libs = 1;
155 } else
Dees_Troy2673cec2013-04-02 20:22:16 +0000156 gui_print("dump_image is already installed, skipping...\n");
Dees_Troy38bd7602012-09-14 13:33:53 -0400157 if (need_libs) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000158 gui_print("Installing libs needed for flash_image and dump_image...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500159 copy_file("/res/htcd/libbmlutils.so", "/system/lib/libbmlutils.so", 0755);
160 copy_file("/res/htcd/libflashutils.so", "/system/lib/libflashutils.so", 0755);
161 copy_file("/res/htcd/libmmcutils.so", "/system/lib/libmmcutils.so", 0755);
162 copy_file("/res/htcd/libmtdutils.so", "/system/lib/libmtdutils.so", 0755);
Dees_Troy38bd7602012-09-14 13:33:53 -0400163 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000164 gui_print("Installing HTC Dumlock app...\n");
Dees_Troy38bd7602012-09-14 13:33:53 -0400165 mkdir("/data/app", 0777);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500166 unlink("/data/app/com.teamwin.htcdumlock*");
167 copy_file("/res/htcd/HTCDumlock.apk", "/data/app/com.teamwin.htcdumlock.apk", 0777);
Dees_Troy38bd7602012-09-14 13:33:53 -0400168 sync();
Dees_Troy2673cec2013-04-02 20:22:16 +0000169 gui_print("HTC Dumlock is installed.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -0400170}
171
172void TWFunc::htc_dumlock_restore_original_boot(void) {
173 if (!PartitionManager.Mount_By_Path("/sdcard", true))
174 return;
175
Dees_Troy2673cec2013-04-02 20:22:16 +0000176 gui_print("Restoring original boot...\n");
Vojtech Bocek05534202013-09-11 08:11:56 +0200177 Exec_Cmd("htcdumlock restore");
Dees_Troy2673cec2013-04-02 20:22:16 +0000178 gui_print("Original boot restored.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -0400179}
180
181void TWFunc::htc_dumlock_reflash_recovery_to_boot(void) {
182 if (!PartitionManager.Mount_By_Path("/sdcard", true))
183 return;
Dees_Troy2673cec2013-04-02 20:22:16 +0000184 gui_print("Reflashing recovery to boot...\n");
Vojtech Bocek05534202013-09-11 08:11:56 +0200185 Exec_Cmd("htcdumlock recovery noreboot");
Dees_Troy2673cec2013-04-02 20:22:16 +0000186 gui_print("Recovery is flashed to boot.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -0400187}
Dees_Troy43d8b002012-09-17 16:00:01 -0400188
189int TWFunc::Recursive_Mkdir(string Path) {
190 string pathCpy = Path;
191 string wholePath;
192 size_t pos = pathCpy.find("/", 2);
193
194 while (pos != string::npos)
195 {
196 wholePath = pathCpy.substr(0, pos);
197 if (mkdir(wholePath.c_str(), 0777) && errno != EEXIST) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000198 LOGERR("Unable to create folder: %s (errno=%d)\n", wholePath.c_str(), errno);
Dees_Troy43d8b002012-09-17 16:00:01 -0400199 return false;
200 }
201
202 pos = pathCpy.find("/", pos + 1);
203 }
204 if (mkdir(wholePath.c_str(), 0777) && errno != EEXIST)
205 return false;
206 return true;
207}
208
Dees_Troy43d8b002012-09-17 16:00:01 -0400209bool TWFunc::Path_Exists(string Path) {
210 // Check to see if the Path exists
Dees_Troy7c2dec82012-09-26 09:49:14 -0400211 struct stat st;
Dees_Troy7c2dec82012-09-26 09:49:14 -0400212 if (stat(Path.c_str(), &st) != 0)
Dees_Troy43d8b002012-09-17 16:00:01 -0400213 return false;
214 else
215 return true;
Dees_Troyb46a6842012-09-25 11:06:46 -0400216}
217
218void TWFunc::GUI_Operation_Text(string Read_Value, string Default_Text) {
219 string Display_Text;
220
221 DataManager::GetValue(Read_Value, Display_Text);
222 if (Display_Text.empty())
223 Display_Text = Default_Text;
224
225 DataManager::SetValue("tw_operation", Display_Text);
226 DataManager::SetValue("tw_partition", "");
227}
228
229void TWFunc::GUI_Operation_Text(string Read_Value, string Partition_Name, string Default_Text) {
230 string Display_Text;
231
232 DataManager::GetValue(Read_Value, Display_Text);
233 if (Display_Text.empty())
234 Display_Text = Default_Text;
235
236 DataManager::SetValue("tw_operation", Display_Text);
237 DataManager::SetValue("tw_partition", Partition_Name);
Dees_Troy7c2dec82012-09-26 09:49:14 -0400238}
239
240unsigned long TWFunc::Get_File_Size(string Path) {
241 struct stat st;
242
243 if (stat(Path.c_str(), &st) != 0)
244 return 0;
245 return st.st_size;
Dees_Troya58bead2012-09-27 09:49:29 -0400246}
247
Dees_Troy2673cec2013-04-02 20:22:16 +0000248void TWFunc::Copy_Log(string Source, string Destination) {
Dees Troy9d7fdf52013-09-19 20:49:25 +0000249 PartitionManager.Mount_By_Path(Destination, false);
Dees_Troy2673cec2013-04-02 20:22:16 +0000250 FILE *destination_log = fopen(Destination.c_str(), "a");
251 if (destination_log == NULL) {
252 LOGERR("TWFunc::Copy_Log -- Can't open destination log file: '%s'\n", Destination.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600253 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000254 FILE *source_log = fopen(Source.c_str(), "r");
255 if (source_log != NULL) {
256 fseek(source_log, Log_Offset, SEEK_SET);
257 char buffer[4096];
258 while (fgets(buffer, sizeof(buffer), source_log))
259 fputs(buffer, destination_log); // Buffered write of log file
260 Log_Offset = ftell(source_log);
261 fflush(source_log);
262 fclose(source_log);
Dees_Troy6ef66352013-02-21 08:26:57 -0600263 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000264 fflush(destination_log);
265 fclose(destination_log);
Dees_Troy6ef66352013-02-21 08:26:57 -0600266 }
Dees_Troya58bead2012-09-27 09:49:29 -0400267}
268
Dees_Troy2673cec2013-04-02 20:22:16 +0000269void TWFunc::Update_Log_File(void) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500270 // Copy logs to cache so the system can find out what happened.
Dees Troy9d7fdf52013-09-19 20:49:25 +0000271 if (PartitionManager.Mount_By_Path("/cache", false)) {
272 if (!TWFunc::Path_Exists("/cache/recovery/.")) {
273 LOGINFO("Recreating /cache/recovery folder.\n");
274 if (mkdir("/cache/recovery", S_IRWXU | S_IRWXG | S_IWGRP | S_IXGRP) != 0)
275 LOGINFO("Unable to create /cache/recovery folder.\n");
276 }
277 Copy_Log(TMP_LOG_FILE, "/cache/recovery/log");
278 copy_file("/cache/recovery/log", "/cache/recovery/last_log", 600);
279 chown("/cache/recovery/log", 1000, 1000);
280 chmod("/cache/recovery/log", 0600);
281 chmod("/cache/recovery/last_log", 0640);
282 } else {
283 LOGINFO("Failed to mount /cache for TWFunc::Update_Log_File\n");
284 }
Dees_Troya58bead2012-09-27 09:49:29 -0400285
Dees_Troy2673cec2013-04-02 20:22:16 +0000286 // Reset bootloader message
287 TWPartition* Part = PartitionManager.Find_Partition_By_Path("/misc");
288 if (Part != NULL) {
289 struct bootloader_message boot;
290 memset(&boot, 0, sizeof(boot));
291 if (Part->Current_File_System == "mtd") {
292 if (set_bootloader_message_mtd_name(&boot, Part->MTD_Name.c_str()) != 0)
293 LOGERR("Unable to set MTD bootloader message.\n");
294 } else if (Part->Current_File_System == "emmc") {
295 if (set_bootloader_message_block_name(&boot, Part->Actual_Block_Device.c_str()) != 0)
296 LOGERR("Unable to set emmc bootloader message.\n");
297 } else {
298 LOGERR("Unknown file system for /misc: '%s'\n", Part->Current_File_System.c_str());
299 }
300 }
Dees_Troya58bead2012-09-27 09:49:29 -0400301
Dees Troy9d7fdf52013-09-19 20:49:25 +0000302 if (PartitionManager.Mount_By_Path("/cache", true)) {
303 if (unlink("/cache/recovery/command") && errno != ENOENT) {
304 LOGINFO("Can't unlink %s\n", "/cache/recovery/command");
305 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500306 }
Dees_Troya58bead2012-09-27 09:49:29 -0400307
Dees_Troy2673cec2013-04-02 20:22:16 +0000308 sync();
309}
310
311void TWFunc::Update_Intent_File(string Intent) {
312 if (PartitionManager.Mount_By_Path("/cache", false) && !Intent.empty()) {
313 TWFunc::write_file("/cache/recovery/intent", Intent);
314 }
Dees_Troya58bead2012-09-27 09:49:29 -0400315}
316
317// reboot: Reboot the system. Return -1 on error, no return on success
318int TWFunc::tw_reboot(RebootCommand command)
319{
320 // Always force a sync before we reboot
Dees_Troy6ef66352013-02-21 08:26:57 -0600321 sync();
Dees_Troya58bead2012-09-27 09:49:29 -0400322
Dees_Troy2673cec2013-04-02 20:22:16 +0000323 switch (command) {
324 case rb_current:
325 case rb_system:
326 Update_Log_File();
327 Update_Intent_File("s");
328 sync();
329 check_and_run_script("/sbin/rebootsystem.sh", "reboot system");
330 return reboot(RB_AUTOBOOT);
331 case rb_recovery:
332 check_and_run_script("/sbin/rebootrecovery.sh", "reboot recovery");
333 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "recovery");
334 case rb_bootloader:
335 check_and_run_script("/sbin/rebootbootloader.sh", "reboot bootloader");
336 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "bootloader");
337 case rb_poweroff:
338 check_and_run_script("/sbin/poweroff.sh", "power off");
Dees_Troya4438782013-02-22 18:44:00 +0000339#ifdef ANDROID_RB_POWEROFF
Dees_Troy2673cec2013-04-02 20:22:16 +0000340 android_reboot(ANDROID_RB_POWEROFF, 0, 0);
Dees_Troya4438782013-02-22 18:44:00 +0000341#endif
Dees_Troy2673cec2013-04-02 20:22:16 +0000342 return reboot(RB_POWER_OFF);
343 case rb_download:
344 check_and_run_script("/sbin/rebootdownload.sh", "reboot download");
345 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "download");
346 default:
347 return -1;
Dees_Troy6ef66352013-02-21 08:26:57 -0600348 }
349 return -1;
Dees_Troya58bead2012-09-27 09:49:29 -0400350}
351
352void TWFunc::check_and_run_script(const char* script_file, const char* display_name)
353{
354 // Check for and run startup script if script exists
355 struct stat st;
356 if (stat(script_file, &st) == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000357 gui_print("Running %s script...\n", display_name);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500358 chmod(script_file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
Vojtech Bocek05534202013-09-11 08:11:56 +0200359 TWFunc::Exec_Cmd(script_file);
Dees_Troy2673cec2013-04-02 20:22:16 +0000360 gui_print("\nFinished running %s script.\n", display_name);
Dees_Troya58bead2012-09-27 09:49:29 -0400361 }
Dees_Troy3477d712012-09-27 15:44:01 -0400362}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500363
364int TWFunc::removeDir(const string path, bool skipParent) {
Dees_Troyce675462013-01-09 19:48:21 +0000365 DIR *d = opendir(path.c_str());
366 int r = 0;
367 string new_path;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500368
Dees_Troyce675462013-01-09 19:48:21 +0000369 if (d == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000370 LOGERR("Error opening '%s'\n", path.c_str());
Dees_Troyce675462013-01-09 19:48:21 +0000371 return -1;
372 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500373
Dees_Troyce675462013-01-09 19:48:21 +0000374 if (d) {
375 struct dirent *p;
376 while (!r && (p = readdir(d))) {
Dees_Troyce675462013-01-09 19:48:21 +0000377 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
378 continue;
379 new_path = path + "/";
380 new_path.append(p->d_name);
381 if (p->d_type == DT_DIR) {
382 r = removeDir(new_path, true);
383 if (!r) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500384 if (p->d_type == DT_DIR)
385 r = rmdir(new_path.c_str());
386 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000387 LOGINFO("Unable to removeDir '%s': %s\n", new_path.c_str(), strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500388 }
bigbiff bigbiff98f1f902013-01-19 18:46:13 -0500389 } else if (p->d_type == DT_REG || p->d_type == DT_LNK || p->d_type == DT_FIFO || p->d_type == DT_SOCK) {
Dees_Troyce675462013-01-09 19:48:21 +0000390 r = unlink(new_path.c_str());
Dees_Troye34c1332013-02-06 19:13:00 +0000391 if (r != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000392 LOGINFO("Unable to unlink '%s: %s'\n", new_path.c_str(), strerror(errno));
Dees_Troye34c1332013-02-06 19:13:00 +0000393 }
Dees_Troyce675462013-01-09 19:48:21 +0000394 }
395 }
396 closedir(d);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500397
398 if (!r) {
399 if (skipParent)
400 return 0;
401 else
402 r = rmdir(path.c_str());
403 }
Dees_Troyce675462013-01-09 19:48:21 +0000404 }
405 return r;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500406}
407
408int TWFunc::copy_file(string src, string dst, int mode) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000409 LOGINFO("Copying file %s to %s\n", src.c_str(), dst.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500410 ifstream srcfile(src.c_str(), ios::binary);
411 ofstream dstfile(dst.c_str(), ios::binary);
412 dstfile << srcfile.rdbuf();
413 srcfile.close();
414 dstfile.close();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500415 if (chmod(dst.c_str(), mode) != 0)
416 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500417 return 0;
418}
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000419
420unsigned int TWFunc::Get_D_Type_From_Stat(string Path) {
421 struct stat st;
422
423 stat(Path.c_str(), &st);
424 if (st.st_mode & S_IFDIR)
425 return DT_DIR;
426 else if (st.st_mode & S_IFBLK)
427 return DT_BLK;
428 else if (st.st_mode & S_IFCHR)
429 return DT_CHR;
430 else if (st.st_mode & S_IFIFO)
431 return DT_FIFO;
432 else if (st.st_mode & S_IFLNK)
433 return DT_LNK;
434 else if (st.st_mode & S_IFREG)
435 return DT_REG;
436 else if (st.st_mode & S_IFSOCK)
437 return DT_SOCK;
438 return DT_UNKNOWN;
Dees_Troye34c1332013-02-06 19:13:00 +0000439}
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500440
441int TWFunc::read_file(string fn, string& results) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200442 ifstream file;
443 file.open(fn.c_str(), ios::in);
444
445 if (file.is_open()) {
446 file >> results;
447 file.close();
448 return 0;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500449 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200450
451 LOGINFO("Cannot find file %s\n", fn.c_str());
452 return -1;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500453}
454
455int TWFunc::read_file(string fn, vector<string>& results) {
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500456 ifstream file;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500457 string line;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500458 file.open(fn.c_str(), ios::in);
459 if (file.is_open()) {
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500460 while (getline(file, line))
461 results.push_back(line);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500462 file.close();
463 return 0;
464 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000465 LOGINFO("Cannot find file %s\n", fn.c_str());
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500466 return -1;
467}
468
469int TWFunc::write_file(string fn, string& line) {
470 FILE *file;
471 file = fopen(fn.c_str(), "w");
472 if (file != NULL) {
473 fwrite(line.c_str(), line.size(), 1, file);
474 fclose(file);
475 return 0;
476 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000477 LOGINFO("Cannot find file %s\n", fn.c_str());
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500478 return -1;
479}
480
Dees_Troy83bd4832013-05-04 12:39:56 +0000481vector<string> TWFunc::split_string(const string &in, char del, bool skip_empty) {
482 vector<string> res;
483
484 if (in.empty() || del == '\0')
485 return res;
486
487 string field;
488 istringstream f(in);
489 if (del == '\n') {
490 while(getline(f, field)) {
491 if (field.empty() && skip_empty)
492 continue;
493 res.push_back(field);
494 }
495 } else {
496 while(getline(f, field, del)) {
497 if (field.empty() && skip_empty)
498 continue;
499 res.push_back(field);
500 }
501 }
502 return res;
503}
504
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500505timespec TWFunc::timespec_diff(timespec& start, timespec& end)
506{
Dees_Troy6ef66352013-02-21 08:26:57 -0600507 timespec temp;
508 if ((end.tv_nsec-start.tv_nsec)<0) {
509 temp.tv_sec = end.tv_sec-start.tv_sec-1;
510 temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
511 } else {
512 temp.tv_sec = end.tv_sec-start.tv_sec;
513 temp.tv_nsec = end.tv_nsec-start.tv_nsec;
514 }
515 return temp;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500516}
517
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100518int32_t TWFunc::timespec_diff_ms(timespec& start, timespec& end)
519{
520 return ((end.tv_sec * 1000) + end.tv_nsec/1000000) -
521 ((start.tv_sec * 1000) + start.tv_nsec/1000000);
522}
523
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200524int TWFunc::drop_caches(void) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600525 string file = "/proc/sys/vm/drop_caches";
526 string value = "3";
527 if (write_file(file, value) != 0)
528 return -1;
529 return 0;
530}
531
532int TWFunc::Check_su_Perms(void) {
533 struct stat st;
534 int ret = 0;
535
536 if (!PartitionManager.Mount_By_Path("/system", false))
537 return 0;
538
539 // Check to ensure that perms are 6755 for all 3 file locations
540 if (stat("/system/bin/su", &st) == 0) {
541 if ((st.st_mode & (S_ISUID | S_ISGID | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) != (S_ISUID | S_ISGID | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) || st.st_uid != 0 || st.st_gid != 0) {
542 ret = 1;
543 }
544 }
545 if (stat("/system/xbin/su", &st) == 0) {
546 if ((st.st_mode & (S_ISUID | S_ISGID | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) != (S_ISUID | S_ISGID | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) || st.st_uid != 0 || st.st_gid != 0) {
547 ret += 2;
548 }
549 }
550 if (stat("/system/bin/.ext/.su", &st) == 0) {
551 if ((st.st_mode & (S_ISUID | S_ISGID | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) != (S_ISUID | S_ISGID | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) || st.st_uid != 0 || st.st_gid != 0) {
552 ret += 4;
553 }
554 }
555 return ret;
556}
557
558bool TWFunc::Fix_su_Perms(void) {
559 if (!PartitionManager.Mount_By_Path("/system", true))
560 return false;
561
562 string file = "/system/bin/su";
563 if (TWFunc::Path_Exists(file)) {
564 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000565 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600566 return false;
567 }
568 if (tw_chmod(file, "6755") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000569 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600570 return false;
571 }
572 }
573 file = "/system/xbin/su";
574 if (TWFunc::Path_Exists(file)) {
575 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000576 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600577 return false;
578 }
579 if (tw_chmod(file, "6755") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000580 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600581 return false;
582 }
583 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000584 file = "/system/xbin/daemonsu";
585 if (TWFunc::Path_Exists(file)) {
586 if (chown(file.c_str(), 0, 0) != 0) {
587 LOGERR("Failed to chown '%s'\n", file.c_str());
588 return false;
589 }
590 if (tw_chmod(file, "6755") != 0) {
591 LOGERR("Failed to chmod '%s'\n", file.c_str());
592 return false;
593 }
594 }
Dees_Troy6ef66352013-02-21 08:26:57 -0600595 file = "/system/bin/.ext/.su";
596 if (TWFunc::Path_Exists(file)) {
597 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000598 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600599 return false;
600 }
601 if (tw_chmod(file, "6755") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000602 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600603 return false;
604 }
605 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000606 file = "/system/etc/install-recovery.sh";
607 if (TWFunc::Path_Exists(file)) {
608 if (chown(file.c_str(), 0, 0) != 0) {
609 LOGERR("Failed to chown '%s'\n", file.c_str());
610 return false;
611 }
612 if (tw_chmod(file, "0755") != 0) {
613 LOGERR("Failed to chmod '%s'\n", file.c_str());
614 return false;
615 }
616 }
617 file = "/system/etc/init.d/99SuperSUDaemon";
618 if (TWFunc::Path_Exists(file)) {
619 if (chown(file.c_str(), 0, 0) != 0) {
620 LOGERR("Failed to chown '%s'\n", file.c_str());
621 return false;
622 }
623 if (tw_chmod(file, "0755") != 0) {
624 LOGERR("Failed to chmod '%s'\n", file.c_str());
625 return false;
626 }
627 }
Dees_Troy6ef66352013-02-21 08:26:57 -0600628 file = "/system/app/Superuser.apk";
629 if (TWFunc::Path_Exists(file)) {
630 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000631 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600632 return false;
633 }
634 if (tw_chmod(file, "0644") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000635 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600636 return false;
637 }
638 }
639 sync();
640 if (!PartitionManager.UnMount_By_Path("/system", true))
641 return false;
642 return true;
643}
644
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200645int TWFunc::tw_chmod(const string& fn, const string& mode) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600646 long mask = 0;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200647 std::string::size_type n = mode.length();
648 int cls = 0;
Dees_Troy6ef66352013-02-21 08:26:57 -0600649
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200650 if(n == 3)
651 ++cls;
652 else if(n != 4)
653 {
654 LOGERR("TWFunc::tw_chmod used with %u long mode string (should be 3 or 4)!\n", mode.length());
655 return -1;
656 }
657
658 for (n = 0; n < mode.length(); ++n, ++cls) {
659 if (cls == 0) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600660 if (mode[n] == '0')
661 continue;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200662 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600663 mask |= S_ISVTX;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200664 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600665 mask |= S_ISGID;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200666 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600667 mask |= S_ISUID;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200668 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600669 mask |= S_ISVTX;
670 mask |= S_ISUID;
671 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200672 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600673 mask |= S_ISGID;
674 mask |= S_ISUID;
675 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200676 else if (mode[n] == '7') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600677 mask |= S_ISVTX;
678 mask |= S_ISGID;
679 mask |= S_ISUID;
680 }
681 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200682 else if (cls == 1) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600683 if (mode[n] == '7') {
684 mask |= S_IRWXU;
685 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200686 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600687 mask |= S_IRUSR;
688 mask |= S_IWUSR;
689 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200690 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600691 mask |= S_IRUSR;
692 mask |= S_IXUSR;
693 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200694 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600695 mask |= S_IRUSR;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200696 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600697 mask |= S_IWUSR;
698 mask |= S_IRUSR;
699 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200700 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600701 mask |= S_IWUSR;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200702 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600703 mask |= S_IXUSR;
704 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200705 else if (cls == 2) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600706 if (mode[n] == '7') {
707 mask |= S_IRWXG;
708 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200709 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600710 mask |= S_IRGRP;
711 mask |= S_IWGRP;
712 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200713 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600714 mask |= S_IRGRP;
715 mask |= S_IXGRP;
716 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200717 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600718 mask |= S_IRGRP;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200719 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600720 mask |= S_IWGRP;
721 mask |= S_IXGRP;
722 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200723 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600724 mask |= S_IWGRP;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200725 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600726 mask |= S_IXGRP;
727 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200728 else if (cls == 3) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600729 if (mode[n] == '7') {
730 mask |= S_IRWXO;
731 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200732 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600733 mask |= S_IROTH;
734 mask |= S_IWOTH;
735 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200736 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600737 mask |= S_IROTH;
738 mask |= S_IXOTH;
739 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200740 else if (mode[n] == '4')
741 mask |= S_IROTH;
742 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600743 mask |= S_IWOTH;
744 mask |= S_IXOTH;
745 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200746 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600747 mask |= S_IWOTH;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200748 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600749 mask |= S_IXOTH;
750 }
751 }
752
753 if (chmod(fn.c_str(), mask) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000754 LOGERR("Unable to chmod '%s' %l\n", fn.c_str(), mask);
Dees_Troy6ef66352013-02-21 08:26:57 -0600755 return -1;
756 }
757
758 return 0;
759}
760
761bool TWFunc::Install_SuperSU(void) {
762 if (!PartitionManager.Mount_By_Path("/system", true))
763 return false;
764
Vojtech Bocek05534202013-09-11 08:11:56 +0200765 TWFunc::Exec_Cmd("/sbin/chattr -i /system/xbin/su");
jt1134113ee732013-02-22 23:26:10 -0600766 if (copy_file("/supersu/su", "/system/xbin/su", 0755) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000767 LOGERR("Failed to copy su binary to /system/bin\n");
Dees_Troy6ef66352013-02-21 08:26:57 -0600768 return false;
769 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000770 if (!Path_Exists("/system/bin/.ext")) {
771 mkdir("/system/bin/.ext", 0777);
772 }
Vojtech Bocek05534202013-09-11 08:11:56 +0200773 TWFunc::Exec_Cmd("/sbin/chattr -i /system/bin/.ext/su");
Dees_Troya7939bb2013-08-29 20:21:12 +0000774 if (copy_file("/supersu/su", "/system/bin/.ext/su", 0755) != 0) {
775 LOGERR("Failed to copy su binary to /system/bin/.ext/su\n");
776 return false;
777 }
Vojtech Bocek05534202013-09-11 08:11:56 +0200778 TWFunc::Exec_Cmd("/sbin/chattr -i /system/xbin/daemonsu");
Dees_Troya7939bb2013-08-29 20:21:12 +0000779 if (copy_file("/supersu/su", "/system/xbin/daemonsu", 0755) != 0) {
780 LOGERR("Failed to copy su binary to /system/xbin/daemonsu\n");
781 return false;
782 }
783 if (Path_Exists("/system/etc/init.d")) {
Vojtech Bocek05534202013-09-11 08:11:56 +0200784 TWFunc::Exec_Cmd("/sbin/chattr -i /system/etc/init.d/99SuperSUDaemon");
Dees_Troya7939bb2013-08-29 20:21:12 +0000785 if (copy_file("/supersu/99SuperSUDaemon", "/system/etc/init.d/99SuperSUDaemon", 0755) != 0) {
786 LOGERR("Failed to copy 99SuperSUDaemon to /system/etc/init.d/99SuperSUDaemon\n");
787 return false;
788 }
789 } else {
Vojtech Bocek05534202013-09-11 08:11:56 +0200790 TWFunc::Exec_Cmd("/sbin/chattr -i /system/etc/install-recovery.sh");
Dees_Troya7939bb2013-08-29 20:21:12 +0000791 if (copy_file("/supersu/install-recovery.sh", "/system/etc/install-recovery.sh", 0755) != 0) {
792 LOGERR("Failed to copy install-recovery.sh to /system/etc/install-recovery.sh\n");
793 return false;
794 }
795 }
jt1134113ee732013-02-22 23:26:10 -0600796 if (copy_file("/supersu/Superuser.apk", "/system/app/Superuser.apk", 0644) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000797 LOGERR("Failed to copy Superuser app to /system/app\n");
Dees_Troy6ef66352013-02-21 08:26:57 -0600798 return false;
799 }
800 if (!Fix_su_Perms())
801 return false;
802 return true;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500803}
Dees_Troy83bd4832013-05-04 12:39:56 +0000804
805int TWFunc::Get_File_Type(string fn) {
806 string::size_type i = 0;
807 int firstbyte = 0, secondbyte = 0;
808 char header[3];
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200809
Dees_Troy83bd4832013-05-04 12:39:56 +0000810 ifstream f;
811 f.open(fn.c_str(), ios::in | ios::binary);
812 f.get(header, 3);
813 f.close();
814 firstbyte = header[i] & 0xff;
815 secondbyte = header[++i] & 0xff;
816
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200817 if (firstbyte == 0x1f && secondbyte == 0x8b)
Dees_Troy83bd4832013-05-04 12:39:56 +0000818 return 1; // Compressed
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200819 else if (firstbyte == 0x4f && secondbyte == 0x41)
Dees_Troy83bd4832013-05-04 12:39:56 +0000820 return 2; // Encrypted
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200821 else
Dees_Troy83bd4832013-05-04 12:39:56 +0000822 return 0; // Unknown
Dees_Troy83bd4832013-05-04 12:39:56 +0000823
824 return 0;
825}
826
827int TWFunc::Try_Decrypting_File(string fn, string password) {
828#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
829 OAES_CTX * ctx = NULL;
830 uint8_t _key_data[32] = "";
831 FILE *f;
832 uint8_t buffer[4096];
833 uint8_t *buffer_out = NULL;
834 uint8_t *ptr = NULL;
835 size_t read_len = 0, out_len = 0;
836 int firstbyte = 0, secondbyte = 0, key_len;
837 size_t _j = 0;
838 size_t _key_data_len = 0;
839
840 // mostly kanged from OpenAES oaes.c
841 for( _j = 0; _j < 32; _j++ )
842 _key_data[_j] = _j + 1;
843 _key_data_len = password.size();
844 if( 16 >= _key_data_len )
845 _key_data_len = 16;
846 else if( 24 >= _key_data_len )
847 _key_data_len = 24;
848 else
849 _key_data_len = 32;
850 memcpy(_key_data, password.c_str(), password.size());
851
852 ctx = oaes_alloc();
853 if (ctx == NULL) {
854 LOGERR("Failed to allocate OAES\n");
855 return -1;
856 }
857
858 oaes_key_import_data(ctx, _key_data, _key_data_len);
859
860 f = fopen(fn.c_str(), "rb");
861 if (f == NULL) {
862 LOGERR("Failed to open '%s' to try decrypt\n", fn.c_str());
863 return -1;
864 }
865 read_len = fread(buffer, sizeof(uint8_t), 4096, f);
866 if (read_len <= 0) {
867 LOGERR("Read size during try decrypt failed\n");
868 fclose(f);
869 return -1;
870 }
871 if (oaes_decrypt(ctx, buffer, read_len, NULL, &out_len) != OAES_RET_SUCCESS) {
872 LOGERR("Error: Failed to retrieve required buffer size for trying decryption.\n");
873 fclose(f);
874 return -1;
875 }
876 buffer_out = (uint8_t *) calloc(out_len, sizeof(char));
877 if (buffer_out == NULL) {
878 LOGERR("Failed to allocate output buffer for try decrypt.\n");
879 fclose(f);
880 return -1;
881 }
882 if (oaes_decrypt(ctx, buffer, read_len, buffer_out, &out_len) != OAES_RET_SUCCESS) {
883 LOGERR("Failed to decrypt file '%s'\n", fn.c_str());
884 fclose(f);
885 free(buffer_out);
886 return 0;
887 }
888 fclose(f);
889 if (out_len < 2) {
890 LOGINFO("Successfully decrypted '%s' but read length %i too small.\n", fn.c_str(), out_len);
891 free(buffer_out);
892 return 1; // Decrypted successfully
893 }
894 ptr = buffer_out;
895 firstbyte = *ptr & 0xff;
896 ptr++;
897 secondbyte = *ptr & 0xff;
898 if (firstbyte == 0x1f && secondbyte == 0x8b) {
899 LOGINFO("Successfully decrypted '%s' and file is compressed.\n", fn.c_str());
900 free(buffer_out);
901 return 3; // Compressed
902 }
903 if (out_len >= 262) {
904 ptr = buffer_out + 257;
905 if (strncmp((char*)ptr, "ustar", 5) == 0) {
906 LOGINFO("Successfully decrypted '%s' and file is tar format.\n", fn.c_str());
907 free(buffer_out);
908 return 2; // Tar
909 }
910 }
911 free(buffer_out);
912 LOGINFO("No errors decrypting '%s' but no known file format.\n", fn.c_str());
913 return 1; // Decrypted successfully
914#else
915 LOGERR("Encrypted backup support not included.\n");
916 return -1;
917#endif
918}
919
920bool TWFunc::Try_Decrypting_Backup(string Restore_Path, string Password) {
921 DIR* d;
922
923 string Filename;
924 Restore_Path += "/";
925 d = opendir(Restore_Path.c_str());
926 if (d == NULL) {
927 LOGERR("Error opening '%s'\n", Restore_Path.c_str());
928 return false;
929 }
930
931 struct dirent* de;
932 while ((de = readdir(d)) != NULL) {
933 Filename = Restore_Path;
934 Filename += de->d_name;
935 if (TWFunc::Get_File_Type(Filename) == 2) {
936 if (TWFunc::Try_Decrypting_File(Filename, Password) < 2) {
937 DataManager::SetValue("tw_restore_password", ""); // Clear the bad password
938 DataManager::SetValue("tw_restore_display", ""); // Also clear the display mask
939 closedir(d);
940 return false;
941 }
942 }
943 }
944 closedir(d);
945 return true;
946}
947
948int TWFunc::Wait_For_Child(pid_t pid, int *status, string Child_Name) {
949 pid_t rc_pid;
950
951 rc_pid = waitpid(pid, status, 0);
952 if (rc_pid > 0) {
953 if (WEXITSTATUS(*status) == 0)
954 LOGINFO("%s process ended with RC=%d\n", Child_Name.c_str(), WEXITSTATUS(*status)); // Success
955 else if (WIFSIGNALED(*status)) {
956 LOGINFO("%s process ended with signal: %d\n", Child_Name.c_str(), WTERMSIG(*status)); // Seg fault or some other non-graceful termination
957 return -1;
958 } else if (WEXITSTATUS(*status) != 0) {
959 LOGINFO("%s process ended with ERROR=%d\n", Child_Name.c_str(), WEXITSTATUS(*status)); // Graceful exit, but there was an error
960 return -1;
961 }
962 } else { // no PID returned
963 if (errno == ECHILD)
964 LOGINFO("%s no child process exist\n", Child_Name.c_str());
965 else {
966 LOGINFO("%s Unexpected error\n", Child_Name.c_str());
967 return -1;
968 }
969 }
970 return 0;
971}
Dees Troyb21cc642013-09-10 17:36:41 +0000972
973string TWFunc::Get_Current_Date() {
974 string Current_Date;
975 time_t seconds = time(0);
976 struct tm *t = localtime(&seconds);
977 char timestamp[255];
978 sprintf(timestamp,"%04d-%02d-%02d--%02d-%02d-%02d",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
979 Current_Date = timestamp;
980 return Current_Date;
981}
982
Ethan Yonkerb5557892014-02-07 21:43:20 -0600983string TWFunc::System_Property_Get(string Prop_Name) {
Dees Troyb21cc642013-09-10 17:36:41 +0000984 bool mount_state = PartitionManager.Is_Mounted_By_Path("/system");
985 std::vector<string> buildprop;
Ethan Yonkerb5557892014-02-07 21:43:20 -0600986 string propvalue;
987 if (!PartitionManager.Mount_By_Path("/system", true))
988 return propvalue;
Dees Troyb21cc642013-09-10 17:36:41 +0000989 if (TWFunc::read_file("/system/build.prop", buildprop) != 0) {
Ethan Yonkerb5557892014-02-07 21:43:20 -0600990 LOGINFO("Unable to open /system/build.prop for getting '%s'.\n", Prop_Name.c_str());
Vojtech Boceka2e70162013-09-17 17:05:10 +0200991 DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
Dees Troyb21cc642013-09-10 17:36:41 +0000992 if (!mount_state)
993 PartitionManager.UnMount_By_Path("/system", false);
Ethan Yonkerb5557892014-02-07 21:43:20 -0600994 return propvalue;
Dees Troyb21cc642013-09-10 17:36:41 +0000995 }
996 int line_count = buildprop.size();
997 int index;
998 size_t start_pos = 0, end_pos;
Ethan Yonkerb5557892014-02-07 21:43:20 -0600999 string propname;
Dees Troyb21cc642013-09-10 17:36:41 +00001000 for (index = 0; index < line_count; index++) {
1001 end_pos = buildprop.at(index).find("=", start_pos);
1002 propname = buildprop.at(index).substr(start_pos, end_pos);
Ethan Yonkerb5557892014-02-07 21:43:20 -06001003 if (propname == Prop_Name) {
Dees Troyb21cc642013-09-10 17:36:41 +00001004 propvalue = buildprop.at(index).substr(end_pos + 1, buildprop.at(index).size());
Ethan Yonkerb5557892014-02-07 21:43:20 -06001005 if (!mount_state)
1006 PartitionManager.UnMount_By_Path("/system", false);
1007 return propvalue;
Dees Troyb21cc642013-09-10 17:36:41 +00001008 }
1009 }
Dees Troyb21cc642013-09-10 17:36:41 +00001010 if (!mount_state)
1011 PartitionManager.UnMount_By_Path("/system", false);
Ethan Yonkerb5557892014-02-07 21:43:20 -06001012 return propvalue;
1013}
1014
1015void TWFunc::Auto_Generate_Backup_Name() {
1016 string propvalue = System_Property_Get("ro.build.display.id");
1017 if (propvalue.empty()) {
1018 DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
1019 return;
1020 }
1021 string Backup_Name = Get_Current_Date();
1022 Backup_Name += " " + propvalue;
1023 if (Backup_Name.size() > MAX_BACKUP_NAME_LEN)
1024 Backup_Name.resize(MAX_BACKUP_NAME_LEN);
1025 // Trailing spaces cause problems on some file systems, so remove them
1026 string space_check, space = " ";
1027 space_check = Backup_Name.substr(Backup_Name.size() - 1, 1);
1028 while (space_check == space) {
1029 Backup_Name.resize(Backup_Name.size() - 1);
1030 space_check = Backup_Name.substr(Backup_Name.size() - 1, 1);
1031 }
1032 DataManager::SetValue(TW_BACKUP_NAME, Backup_Name);
Vojtech Bocek05534202013-09-11 08:11:56 +02001033}
Vojtech Bocekd0e38bc2014-02-03 23:36:57 +01001034
1035void TWFunc::Fixup_Time_On_Boot()
1036{
1037#ifdef QCOM_RTC_FIX
1038 // Devices with Qualcomm Snapdragon 800 do some shenanigans with RTC.
1039 // They never set it, it just ticks forward from 1970-01-01 00:00,
1040 // and then they have files /data/system/time/ats_* with 64bit offset
1041 // in miliseconds which, when added to the RTC, gives the correct time.
1042 // So, the time is: (offset_from_ats + value_from_RTC)
1043 // There are multiple ats files, they are for different systems? Bases?
1044 // Like, ats_1 is for modem and ats_2 is for TOD (time of day?).
1045 // Look at file time_genoff.h in CodeAurora, qcom-opensource/time-services
1046
1047 static const char *paths[] = { "/data/system/time/", "/data/time/" };
1048
1049 DIR *d;
1050 FILE *f;
1051 uint64_t offset = 0;
1052 struct timeval tv;
1053 struct dirent *dt;
1054 std::string ats_path;
1055
1056
1057 // Don't fix the time of it already is over year 2000, it is likely already okay, either
1058 // because the RTC is fine or because the recovery already set it and then crashed
1059 gettimeofday(&tv, NULL);
1060 if(tv.tv_sec > 946684800) // timestamp of 2000-01-01 00:00:00
1061 {
1062 LOGINFO("TWFunc::Fixup_Time: not fixing time, it seems to be already okay (after year 2000).\n");
1063 return;
1064 }
1065
1066 if(!PartitionManager.Mount_By_Path("/data", false))
1067 return;
1068
1069 // Prefer ats_2, it seems to be the one we want according to logcat on hammerhead
1070 // - it is the one for ATS_TOD (time of day?).
1071 // However, I never saw a device where the offset differs between ats files.
1072 for(size_t i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i)
1073 {
1074 DIR *d = opendir(paths[i]);
1075 if(!d)
1076 continue;
1077
1078 while((dt = readdir(d)))
1079 {
1080 if(dt->d_type != DT_REG || strncmp(dt->d_name, "ats_", 4) != 0)
1081 continue;
1082
1083 if(ats_path.empty() || strcmp(dt->d_name, "ats_2") == 0)
1084 ats_path = std::string(paths[i]).append(dt->d_name);
1085 }
1086
1087 closedir(d);
1088 }
1089
1090 if(ats_path.empty())
1091 {
1092 LOGERR("TWFunc::Fixup_Time: no ats files found, leaving time as-is!\n");
1093 return;
1094 }
1095
1096 f = fopen(ats_path.c_str(), "r");
1097 if(!f)
1098 {
1099 LOGERR("TWFunc::Fixup_Time: failed to open file %s\n", ats_path.c_str());
1100 return;
1101 }
1102
1103 if(fread(&offset, sizeof(offset), 1, f) != 1)
1104 {
1105 LOGERR("TWFunc::Fixup_Time: failed load uint64 from file %s\n", ats_path.c_str());
1106 fclose(f);
1107 return;
1108 }
1109 fclose(f);
1110
1111 LOGINFO("TWFunc::Fixup_Time: Setting time offset from file %s, offset %llu\n", ats_path.c_str(), offset);
1112
1113 gettimeofday(&tv, NULL);
1114
1115 tv.tv_sec += offset/1000;
1116 tv.tv_usec += (offset%1000)*1000;
1117
1118 while(tv.tv_usec >= 1000000)
1119 {
1120 ++tv.tv_sec;
1121 tv.tv_usec -= 1000000;
1122 }
1123
1124 settimeofday(&tv, NULL);
1125#endif
1126}