blob: 3f44fd2ce013d818396a7041cb9fea0df26277f6 [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 Bocekfafb0c52013-07-25 22:53:02 +0200518int TWFunc::drop_caches(void) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600519 string file = "/proc/sys/vm/drop_caches";
520 string value = "3";
521 if (write_file(file, value) != 0)
522 return -1;
523 return 0;
524}
525
526int TWFunc::Check_su_Perms(void) {
527 struct stat st;
528 int ret = 0;
529
530 if (!PartitionManager.Mount_By_Path("/system", false))
531 return 0;
532
533 // Check to ensure that perms are 6755 for all 3 file locations
534 if (stat("/system/bin/su", &st) == 0) {
535 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) {
536 ret = 1;
537 }
538 }
539 if (stat("/system/xbin/su", &st) == 0) {
540 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) {
541 ret += 2;
542 }
543 }
544 if (stat("/system/bin/.ext/.su", &st) == 0) {
545 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) {
546 ret += 4;
547 }
548 }
549 return ret;
550}
551
552bool TWFunc::Fix_su_Perms(void) {
553 if (!PartitionManager.Mount_By_Path("/system", true))
554 return false;
555
556 string file = "/system/bin/su";
557 if (TWFunc::Path_Exists(file)) {
558 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000559 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600560 return false;
561 }
562 if (tw_chmod(file, "6755") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000563 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600564 return false;
565 }
566 }
567 file = "/system/xbin/su";
568 if (TWFunc::Path_Exists(file)) {
569 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000570 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600571 return false;
572 }
573 if (tw_chmod(file, "6755") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000574 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600575 return false;
576 }
577 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000578 file = "/system/xbin/daemonsu";
579 if (TWFunc::Path_Exists(file)) {
580 if (chown(file.c_str(), 0, 0) != 0) {
581 LOGERR("Failed to chown '%s'\n", file.c_str());
582 return false;
583 }
584 if (tw_chmod(file, "6755") != 0) {
585 LOGERR("Failed to chmod '%s'\n", file.c_str());
586 return false;
587 }
588 }
Dees_Troy6ef66352013-02-21 08:26:57 -0600589 file = "/system/bin/.ext/.su";
590 if (TWFunc::Path_Exists(file)) {
591 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000592 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600593 return false;
594 }
595 if (tw_chmod(file, "6755") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000596 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600597 return false;
598 }
599 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000600 file = "/system/etc/install-recovery.sh";
601 if (TWFunc::Path_Exists(file)) {
602 if (chown(file.c_str(), 0, 0) != 0) {
603 LOGERR("Failed to chown '%s'\n", file.c_str());
604 return false;
605 }
606 if (tw_chmod(file, "0755") != 0) {
607 LOGERR("Failed to chmod '%s'\n", file.c_str());
608 return false;
609 }
610 }
611 file = "/system/etc/init.d/99SuperSUDaemon";
612 if (TWFunc::Path_Exists(file)) {
613 if (chown(file.c_str(), 0, 0) != 0) {
614 LOGERR("Failed to chown '%s'\n", file.c_str());
615 return false;
616 }
617 if (tw_chmod(file, "0755") != 0) {
618 LOGERR("Failed to chmod '%s'\n", file.c_str());
619 return false;
620 }
621 }
Dees_Troy6ef66352013-02-21 08:26:57 -0600622 file = "/system/app/Superuser.apk";
623 if (TWFunc::Path_Exists(file)) {
624 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000625 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600626 return false;
627 }
628 if (tw_chmod(file, "0644") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000629 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600630 return false;
631 }
632 }
633 sync();
634 if (!PartitionManager.UnMount_By_Path("/system", true))
635 return false;
636 return true;
637}
638
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200639int TWFunc::tw_chmod(const string& fn, const string& mode) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600640 long mask = 0;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200641 std::string::size_type n = mode.length();
642 int cls = 0;
Dees_Troy6ef66352013-02-21 08:26:57 -0600643
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200644 if(n == 3)
645 ++cls;
646 else if(n != 4)
647 {
648 LOGERR("TWFunc::tw_chmod used with %u long mode string (should be 3 or 4)!\n", mode.length());
649 return -1;
650 }
651
652 for (n = 0; n < mode.length(); ++n, ++cls) {
653 if (cls == 0) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600654 if (mode[n] == '0')
655 continue;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200656 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600657 mask |= S_ISVTX;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200658 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600659 mask |= S_ISGID;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200660 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600661 mask |= S_ISUID;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200662 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600663 mask |= S_ISVTX;
664 mask |= S_ISUID;
665 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200666 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600667 mask |= S_ISGID;
668 mask |= S_ISUID;
669 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200670 else if (mode[n] == '7') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600671 mask |= S_ISVTX;
672 mask |= S_ISGID;
673 mask |= S_ISUID;
674 }
675 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200676 else if (cls == 1) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600677 if (mode[n] == '7') {
678 mask |= S_IRWXU;
679 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200680 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600681 mask |= S_IRUSR;
682 mask |= S_IWUSR;
683 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200684 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600685 mask |= S_IRUSR;
686 mask |= S_IXUSR;
687 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200688 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600689 mask |= S_IRUSR;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200690 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600691 mask |= S_IWUSR;
692 mask |= S_IRUSR;
693 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200694 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600695 mask |= S_IWUSR;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200696 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600697 mask |= S_IXUSR;
698 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200699 else if (cls == 2) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600700 if (mode[n] == '7') {
701 mask |= S_IRWXG;
702 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200703 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600704 mask |= S_IRGRP;
705 mask |= S_IWGRP;
706 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200707 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600708 mask |= S_IRGRP;
709 mask |= S_IXGRP;
710 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200711 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600712 mask |= S_IRGRP;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200713 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600714 mask |= S_IWGRP;
715 mask |= S_IXGRP;
716 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200717 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600718 mask |= S_IWGRP;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200719 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600720 mask |= S_IXGRP;
721 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200722 else if (cls == 3) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600723 if (mode[n] == '7') {
724 mask |= S_IRWXO;
725 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200726 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600727 mask |= S_IROTH;
728 mask |= S_IWOTH;
729 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200730 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600731 mask |= S_IROTH;
732 mask |= S_IXOTH;
733 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200734 else if (mode[n] == '4')
735 mask |= S_IROTH;
736 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600737 mask |= S_IWOTH;
738 mask |= S_IXOTH;
739 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200740 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600741 mask |= S_IWOTH;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200742 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600743 mask |= S_IXOTH;
744 }
745 }
746
747 if (chmod(fn.c_str(), mask) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000748 LOGERR("Unable to chmod '%s' %l\n", fn.c_str(), mask);
Dees_Troy6ef66352013-02-21 08:26:57 -0600749 return -1;
750 }
751
752 return 0;
753}
754
755bool TWFunc::Install_SuperSU(void) {
756 if (!PartitionManager.Mount_By_Path("/system", true))
757 return false;
758
Vojtech Bocek05534202013-09-11 08:11:56 +0200759 TWFunc::Exec_Cmd("/sbin/chattr -i /system/xbin/su");
jt1134113ee732013-02-22 23:26:10 -0600760 if (copy_file("/supersu/su", "/system/xbin/su", 0755) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000761 LOGERR("Failed to copy su binary to /system/bin\n");
Dees_Troy6ef66352013-02-21 08:26:57 -0600762 return false;
763 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000764 if (!Path_Exists("/system/bin/.ext")) {
765 mkdir("/system/bin/.ext", 0777);
766 }
Vojtech Bocek05534202013-09-11 08:11:56 +0200767 TWFunc::Exec_Cmd("/sbin/chattr -i /system/bin/.ext/su");
Dees_Troya7939bb2013-08-29 20:21:12 +0000768 if (copy_file("/supersu/su", "/system/bin/.ext/su", 0755) != 0) {
769 LOGERR("Failed to copy su binary to /system/bin/.ext/su\n");
770 return false;
771 }
Vojtech Bocek05534202013-09-11 08:11:56 +0200772 TWFunc::Exec_Cmd("/sbin/chattr -i /system/xbin/daemonsu");
Dees_Troya7939bb2013-08-29 20:21:12 +0000773 if (copy_file("/supersu/su", "/system/xbin/daemonsu", 0755) != 0) {
774 LOGERR("Failed to copy su binary to /system/xbin/daemonsu\n");
775 return false;
776 }
777 if (Path_Exists("/system/etc/init.d")) {
Vojtech Bocek05534202013-09-11 08:11:56 +0200778 TWFunc::Exec_Cmd("/sbin/chattr -i /system/etc/init.d/99SuperSUDaemon");
Dees_Troya7939bb2013-08-29 20:21:12 +0000779 if (copy_file("/supersu/99SuperSUDaemon", "/system/etc/init.d/99SuperSUDaemon", 0755) != 0) {
780 LOGERR("Failed to copy 99SuperSUDaemon to /system/etc/init.d/99SuperSUDaemon\n");
781 return false;
782 }
783 } else {
Vojtech Bocek05534202013-09-11 08:11:56 +0200784 TWFunc::Exec_Cmd("/sbin/chattr -i /system/etc/install-recovery.sh");
Dees_Troya7939bb2013-08-29 20:21:12 +0000785 if (copy_file("/supersu/install-recovery.sh", "/system/etc/install-recovery.sh", 0755) != 0) {
786 LOGERR("Failed to copy install-recovery.sh to /system/etc/install-recovery.sh\n");
787 return false;
788 }
789 }
jt1134113ee732013-02-22 23:26:10 -0600790 if (copy_file("/supersu/Superuser.apk", "/system/app/Superuser.apk", 0644) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000791 LOGERR("Failed to copy Superuser app to /system/app\n");
Dees_Troy6ef66352013-02-21 08:26:57 -0600792 return false;
793 }
794 if (!Fix_su_Perms())
795 return false;
796 return true;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500797}
Dees_Troy83bd4832013-05-04 12:39:56 +0000798
799int TWFunc::Get_File_Type(string fn) {
800 string::size_type i = 0;
801 int firstbyte = 0, secondbyte = 0;
802 char header[3];
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200803
Dees_Troy83bd4832013-05-04 12:39:56 +0000804 ifstream f;
805 f.open(fn.c_str(), ios::in | ios::binary);
806 f.get(header, 3);
807 f.close();
808 firstbyte = header[i] & 0xff;
809 secondbyte = header[++i] & 0xff;
810
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200811 if (firstbyte == 0x1f && secondbyte == 0x8b)
Dees_Troy83bd4832013-05-04 12:39:56 +0000812 return 1; // Compressed
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200813 else if (firstbyte == 0x4f && secondbyte == 0x41)
Dees_Troy83bd4832013-05-04 12:39:56 +0000814 return 2; // Encrypted
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200815 else
Dees_Troy83bd4832013-05-04 12:39:56 +0000816 return 0; // Unknown
Dees_Troy83bd4832013-05-04 12:39:56 +0000817
818 return 0;
819}
820
821int TWFunc::Try_Decrypting_File(string fn, string password) {
822#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
823 OAES_CTX * ctx = NULL;
824 uint8_t _key_data[32] = "";
825 FILE *f;
826 uint8_t buffer[4096];
827 uint8_t *buffer_out = NULL;
828 uint8_t *ptr = NULL;
829 size_t read_len = 0, out_len = 0;
830 int firstbyte = 0, secondbyte = 0, key_len;
831 size_t _j = 0;
832 size_t _key_data_len = 0;
833
834 // mostly kanged from OpenAES oaes.c
835 for( _j = 0; _j < 32; _j++ )
836 _key_data[_j] = _j + 1;
837 _key_data_len = password.size();
838 if( 16 >= _key_data_len )
839 _key_data_len = 16;
840 else if( 24 >= _key_data_len )
841 _key_data_len = 24;
842 else
843 _key_data_len = 32;
844 memcpy(_key_data, password.c_str(), password.size());
845
846 ctx = oaes_alloc();
847 if (ctx == NULL) {
848 LOGERR("Failed to allocate OAES\n");
849 return -1;
850 }
851
852 oaes_key_import_data(ctx, _key_data, _key_data_len);
853
854 f = fopen(fn.c_str(), "rb");
855 if (f == NULL) {
856 LOGERR("Failed to open '%s' to try decrypt\n", fn.c_str());
857 return -1;
858 }
859 read_len = fread(buffer, sizeof(uint8_t), 4096, f);
860 if (read_len <= 0) {
861 LOGERR("Read size during try decrypt failed\n");
862 fclose(f);
863 return -1;
864 }
865 if (oaes_decrypt(ctx, buffer, read_len, NULL, &out_len) != OAES_RET_SUCCESS) {
866 LOGERR("Error: Failed to retrieve required buffer size for trying decryption.\n");
867 fclose(f);
868 return -1;
869 }
870 buffer_out = (uint8_t *) calloc(out_len, sizeof(char));
871 if (buffer_out == NULL) {
872 LOGERR("Failed to allocate output buffer for try decrypt.\n");
873 fclose(f);
874 return -1;
875 }
876 if (oaes_decrypt(ctx, buffer, read_len, buffer_out, &out_len) != OAES_RET_SUCCESS) {
877 LOGERR("Failed to decrypt file '%s'\n", fn.c_str());
878 fclose(f);
879 free(buffer_out);
880 return 0;
881 }
882 fclose(f);
883 if (out_len < 2) {
884 LOGINFO("Successfully decrypted '%s' but read length %i too small.\n", fn.c_str(), out_len);
885 free(buffer_out);
886 return 1; // Decrypted successfully
887 }
888 ptr = buffer_out;
889 firstbyte = *ptr & 0xff;
890 ptr++;
891 secondbyte = *ptr & 0xff;
892 if (firstbyte == 0x1f && secondbyte == 0x8b) {
893 LOGINFO("Successfully decrypted '%s' and file is compressed.\n", fn.c_str());
894 free(buffer_out);
895 return 3; // Compressed
896 }
897 if (out_len >= 262) {
898 ptr = buffer_out + 257;
899 if (strncmp((char*)ptr, "ustar", 5) == 0) {
900 LOGINFO("Successfully decrypted '%s' and file is tar format.\n", fn.c_str());
901 free(buffer_out);
902 return 2; // Tar
903 }
904 }
905 free(buffer_out);
906 LOGINFO("No errors decrypting '%s' but no known file format.\n", fn.c_str());
907 return 1; // Decrypted successfully
908#else
909 LOGERR("Encrypted backup support not included.\n");
910 return -1;
911#endif
912}
913
914bool TWFunc::Try_Decrypting_Backup(string Restore_Path, string Password) {
915 DIR* d;
916
917 string Filename;
918 Restore_Path += "/";
919 d = opendir(Restore_Path.c_str());
920 if (d == NULL) {
921 LOGERR("Error opening '%s'\n", Restore_Path.c_str());
922 return false;
923 }
924
925 struct dirent* de;
926 while ((de = readdir(d)) != NULL) {
927 Filename = Restore_Path;
928 Filename += de->d_name;
929 if (TWFunc::Get_File_Type(Filename) == 2) {
930 if (TWFunc::Try_Decrypting_File(Filename, Password) < 2) {
931 DataManager::SetValue("tw_restore_password", ""); // Clear the bad password
932 DataManager::SetValue("tw_restore_display", ""); // Also clear the display mask
933 closedir(d);
934 return false;
935 }
936 }
937 }
938 closedir(d);
939 return true;
940}
941
942int TWFunc::Wait_For_Child(pid_t pid, int *status, string Child_Name) {
943 pid_t rc_pid;
944
945 rc_pid = waitpid(pid, status, 0);
946 if (rc_pid > 0) {
947 if (WEXITSTATUS(*status) == 0)
948 LOGINFO("%s process ended with RC=%d\n", Child_Name.c_str(), WEXITSTATUS(*status)); // Success
949 else if (WIFSIGNALED(*status)) {
950 LOGINFO("%s process ended with signal: %d\n", Child_Name.c_str(), WTERMSIG(*status)); // Seg fault or some other non-graceful termination
951 return -1;
952 } else if (WEXITSTATUS(*status) != 0) {
953 LOGINFO("%s process ended with ERROR=%d\n", Child_Name.c_str(), WEXITSTATUS(*status)); // Graceful exit, but there was an error
954 return -1;
955 }
956 } else { // no PID returned
957 if (errno == ECHILD)
958 LOGINFO("%s no child process exist\n", Child_Name.c_str());
959 else {
960 LOGINFO("%s Unexpected error\n", Child_Name.c_str());
961 return -1;
962 }
963 }
964 return 0;
965}
Dees Troyb21cc642013-09-10 17:36:41 +0000966
967string TWFunc::Get_Current_Date() {
968 string Current_Date;
969 time_t seconds = time(0);
970 struct tm *t = localtime(&seconds);
971 char timestamp[255];
972 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);
973 Current_Date = timestamp;
974 return Current_Date;
975}
976
977void TWFunc::Auto_Generate_Backup_Name() {
978 bool mount_state = PartitionManager.Is_Mounted_By_Path("/system");
979 std::vector<string> buildprop;
980 if (!PartitionManager.Mount_By_Path("/system", true)) {
981 DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
982 return;
983 }
984 if (TWFunc::read_file("/system/build.prop", buildprop) != 0) {
985 LOGINFO("Unable to open /system/build.prop for getting backup name.\n");
Vojtech Boceka2e70162013-09-17 17:05:10 +0200986 DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
Dees Troyb21cc642013-09-10 17:36:41 +0000987 if (!mount_state)
988 PartitionManager.UnMount_By_Path("/system", false);
989 return;
990 }
991 int line_count = buildprop.size();
992 int index;
993 size_t start_pos = 0, end_pos;
994 string propname, propvalue;
995 for (index = 0; index < line_count; index++) {
996 end_pos = buildprop.at(index).find("=", start_pos);
997 propname = buildprop.at(index).substr(start_pos, end_pos);
998 if (propname == "ro.build.display.id") {
999 propvalue = buildprop.at(index).substr(end_pos + 1, buildprop.at(index).size());
1000 string Backup_Name = Get_Current_Date();
1001 Backup_Name += " " + propvalue;
1002 if (Backup_Name.size() > MAX_BACKUP_NAME_LEN)
1003 Backup_Name.resize(MAX_BACKUP_NAME_LEN);
Dees Troya829d5d2013-10-17 00:26:23 +00001004 // Trailing spaces cause problems on some file systems, so remove them
1005 string space_check, space = " ";
1006 space_check = Backup_Name.substr(Backup_Name.size() - 1, 1);
1007 while (space_check == space) {
1008 Backup_Name.resize(Backup_Name.size() - 1);
1009 space_check = Backup_Name.substr(Backup_Name.size() - 1, 1);
1010 }
Dees Troyb21cc642013-09-10 17:36:41 +00001011 DataManager::SetValue(TW_BACKUP_NAME, Backup_Name);
1012 break;
1013 }
1014 }
1015 if (propvalue.empty()) {
1016 LOGINFO("ro.build.display.id not found in build.prop\n");
Vojtech Boceka2e70162013-09-17 17:05:10 +02001017 DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
Dees Troyb21cc642013-09-10 17:36:41 +00001018 }
1019 if (!mount_state)
1020 PartitionManager.UnMount_By_Path("/system", false);
Vojtech Bocek05534202013-09-11 08:11:56 +02001021}
Vojtech Bocekd0e38bc2014-02-03 23:36:57 +01001022
1023void TWFunc::Fixup_Time_On_Boot()
1024{
1025#ifdef QCOM_RTC_FIX
1026 // Devices with Qualcomm Snapdragon 800 do some shenanigans with RTC.
1027 // They never set it, it just ticks forward from 1970-01-01 00:00,
1028 // and then they have files /data/system/time/ats_* with 64bit offset
1029 // in miliseconds which, when added to the RTC, gives the correct time.
1030 // So, the time is: (offset_from_ats + value_from_RTC)
1031 // There are multiple ats files, they are for different systems? Bases?
1032 // Like, ats_1 is for modem and ats_2 is for TOD (time of day?).
1033 // Look at file time_genoff.h in CodeAurora, qcom-opensource/time-services
1034
1035 static const char *paths[] = { "/data/system/time/", "/data/time/" };
1036
1037 DIR *d;
1038 FILE *f;
1039 uint64_t offset = 0;
1040 struct timeval tv;
1041 struct dirent *dt;
1042 std::string ats_path;
1043
1044
1045 // Don't fix the time of it already is over year 2000, it is likely already okay, either
1046 // because the RTC is fine or because the recovery already set it and then crashed
1047 gettimeofday(&tv, NULL);
1048 if(tv.tv_sec > 946684800) // timestamp of 2000-01-01 00:00:00
1049 {
1050 LOGINFO("TWFunc::Fixup_Time: not fixing time, it seems to be already okay (after year 2000).\n");
1051 return;
1052 }
1053
1054 if(!PartitionManager.Mount_By_Path("/data", false))
1055 return;
1056
1057 // Prefer ats_2, it seems to be the one we want according to logcat on hammerhead
1058 // - it is the one for ATS_TOD (time of day?).
1059 // However, I never saw a device where the offset differs between ats files.
1060 for(size_t i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i)
1061 {
1062 DIR *d = opendir(paths[i]);
1063 if(!d)
1064 continue;
1065
1066 while((dt = readdir(d)))
1067 {
1068 if(dt->d_type != DT_REG || strncmp(dt->d_name, "ats_", 4) != 0)
1069 continue;
1070
1071 if(ats_path.empty() || strcmp(dt->d_name, "ats_2") == 0)
1072 ats_path = std::string(paths[i]).append(dt->d_name);
1073 }
1074
1075 closedir(d);
1076 }
1077
1078 if(ats_path.empty())
1079 {
1080 LOGERR("TWFunc::Fixup_Time: no ats files found, leaving time as-is!\n");
1081 return;
1082 }
1083
1084 f = fopen(ats_path.c_str(), "r");
1085 if(!f)
1086 {
1087 LOGERR("TWFunc::Fixup_Time: failed to open file %s\n", ats_path.c_str());
1088 return;
1089 }
1090
1091 if(fread(&offset, sizeof(offset), 1, f) != 1)
1092 {
1093 LOGERR("TWFunc::Fixup_Time: failed load uint64 from file %s\n", ats_path.c_str());
1094 fclose(f);
1095 return;
1096 }
1097 fclose(f);
1098
1099 LOGINFO("TWFunc::Fixup_Time: Setting time offset from file %s, offset %llu\n", ats_path.c_str(), offset);
1100
1101 gettimeofday(&tv, NULL);
1102
1103 tv.tv_sec += offset/1000;
1104 tv.tv_usec += (offset%1000)*1000;
1105
1106 while(tv.tv_usec >= 1000000)
1107 {
1108 ++tv.tv_sec;
1109 tv.tv_usec -= 1000000;
1110 }
1111
1112 settimeofday(&tv, NULL);
1113#endif
1114}