blob: f0c8cd43094eec49f30bafa49aa5a0dd22f7bc4c [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
Vojtech Bocek2e97ec52013-02-02 13:22:42 +0100209unsigned long long TWFunc::Get_Folder_Size(const string& Path, bool Display_Error) {
Dees_Troy43d8b002012-09-17 16:00:01 -0400210 DIR* d;
211 struct dirent* de;
212 struct stat st;
Dees_Troy43d8b002012-09-17 16:00:01 -0400213 unsigned long long dusize = 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500214 unsigned long long dutemp = 0;
Dees_Troy43d8b002012-09-17 16:00:01 -0400215
Vojtech Bocek2e97ec52013-02-02 13:22:42 +0100216 d = opendir(Path.c_str());
Dees_Troy43d8b002012-09-17 16:00:01 -0400217 if (d == NULL)
218 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000219 LOGERR("error opening '%s'\n", Path.c_str());
220 LOGERR("error: %s\n", strerror(errno));
Dees_Troy43d8b002012-09-17 16:00:01 -0400221 return 0;
222 }
223
224 while ((de = readdir(d)) != NULL)
225 {
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400226 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+found") != 0)
Dees_Troy43d8b002012-09-17 16:00:01 -0400227 {
Vojtech Bocek2e97ec52013-02-02 13:22:42 +0100228 dutemp = Get_Folder_Size((Path + "/" + de->d_name), Display_Error);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500229 dusize += dutemp;
230 dutemp = 0;
Dees_Troy43d8b002012-09-17 16:00:01 -0400231 }
232 else if (de->d_type == DT_REG)
233 {
Vojtech Bocek2e97ec52013-02-02 13:22:42 +0100234 stat((Path + "/" + de->d_name).c_str(), &st);
Dees_Troy43d8b002012-09-17 16:00:01 -0400235 dusize += (unsigned long long)(st.st_size);
236 }
237 }
238 closedir(d);
Dees_Troy43d8b002012-09-17 16:00:01 -0400239 return dusize;
240}
241
242bool TWFunc::Path_Exists(string Path) {
243 // Check to see if the Path exists
Dees_Troy7c2dec82012-09-26 09:49:14 -0400244 struct stat st;
Dees_Troy7c2dec82012-09-26 09:49:14 -0400245 if (stat(Path.c_str(), &st) != 0)
Dees_Troy43d8b002012-09-17 16:00:01 -0400246 return false;
247 else
248 return true;
Dees_Troyb46a6842012-09-25 11:06:46 -0400249}
250
251void TWFunc::GUI_Operation_Text(string Read_Value, string Default_Text) {
252 string Display_Text;
253
254 DataManager::GetValue(Read_Value, Display_Text);
255 if (Display_Text.empty())
256 Display_Text = Default_Text;
257
258 DataManager::SetValue("tw_operation", Display_Text);
259 DataManager::SetValue("tw_partition", "");
260}
261
262void TWFunc::GUI_Operation_Text(string Read_Value, string Partition_Name, string Default_Text) {
263 string Display_Text;
264
265 DataManager::GetValue(Read_Value, Display_Text);
266 if (Display_Text.empty())
267 Display_Text = Default_Text;
268
269 DataManager::SetValue("tw_operation", Display_Text);
270 DataManager::SetValue("tw_partition", Partition_Name);
Dees_Troy7c2dec82012-09-26 09:49:14 -0400271}
272
273unsigned long TWFunc::Get_File_Size(string Path) {
274 struct stat st;
275
276 if (stat(Path.c_str(), &st) != 0)
277 return 0;
278 return st.st_size;
Dees_Troya58bead2012-09-27 09:49:29 -0400279}
280
Dees_Troy2673cec2013-04-02 20:22:16 +0000281void TWFunc::Copy_Log(string Source, string Destination) {
Dees Troy9d7fdf52013-09-19 20:49:25 +0000282 PartitionManager.Mount_By_Path(Destination, false);
Dees_Troy2673cec2013-04-02 20:22:16 +0000283 FILE *destination_log = fopen(Destination.c_str(), "a");
284 if (destination_log == NULL) {
285 LOGERR("TWFunc::Copy_Log -- Can't open destination log file: '%s'\n", Destination.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600286 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000287 FILE *source_log = fopen(Source.c_str(), "r");
288 if (source_log != NULL) {
289 fseek(source_log, Log_Offset, SEEK_SET);
290 char buffer[4096];
291 while (fgets(buffer, sizeof(buffer), source_log))
292 fputs(buffer, destination_log); // Buffered write of log file
293 Log_Offset = ftell(source_log);
294 fflush(source_log);
295 fclose(source_log);
Dees_Troy6ef66352013-02-21 08:26:57 -0600296 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000297 fflush(destination_log);
298 fclose(destination_log);
Dees_Troy6ef66352013-02-21 08:26:57 -0600299 }
Dees_Troya58bead2012-09-27 09:49:29 -0400300}
301
Dees_Troy2673cec2013-04-02 20:22:16 +0000302void TWFunc::Update_Log_File(void) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500303 // Copy logs to cache so the system can find out what happened.
Dees Troy9d7fdf52013-09-19 20:49:25 +0000304 if (PartitionManager.Mount_By_Path("/cache", false)) {
305 if (!TWFunc::Path_Exists("/cache/recovery/.")) {
306 LOGINFO("Recreating /cache/recovery folder.\n");
307 if (mkdir("/cache/recovery", S_IRWXU | S_IRWXG | S_IWGRP | S_IXGRP) != 0)
308 LOGINFO("Unable to create /cache/recovery folder.\n");
309 }
310 Copy_Log(TMP_LOG_FILE, "/cache/recovery/log");
311 copy_file("/cache/recovery/log", "/cache/recovery/last_log", 600);
312 chown("/cache/recovery/log", 1000, 1000);
313 chmod("/cache/recovery/log", 0600);
314 chmod("/cache/recovery/last_log", 0640);
315 } else {
316 LOGINFO("Failed to mount /cache for TWFunc::Update_Log_File\n");
317 }
Dees_Troya58bead2012-09-27 09:49:29 -0400318
Dees_Troy2673cec2013-04-02 20:22:16 +0000319 // Reset bootloader message
320 TWPartition* Part = PartitionManager.Find_Partition_By_Path("/misc");
321 if (Part != NULL) {
322 struct bootloader_message boot;
323 memset(&boot, 0, sizeof(boot));
324 if (Part->Current_File_System == "mtd") {
325 if (set_bootloader_message_mtd_name(&boot, Part->MTD_Name.c_str()) != 0)
326 LOGERR("Unable to set MTD bootloader message.\n");
327 } else if (Part->Current_File_System == "emmc") {
328 if (set_bootloader_message_block_name(&boot, Part->Actual_Block_Device.c_str()) != 0)
329 LOGERR("Unable to set emmc bootloader message.\n");
330 } else {
331 LOGERR("Unknown file system for /misc: '%s'\n", Part->Current_File_System.c_str());
332 }
333 }
Dees_Troya58bead2012-09-27 09:49:29 -0400334
Dees Troy9d7fdf52013-09-19 20:49:25 +0000335 if (PartitionManager.Mount_By_Path("/cache", true)) {
336 if (unlink("/cache/recovery/command") && errno != ENOENT) {
337 LOGINFO("Can't unlink %s\n", "/cache/recovery/command");
338 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500339 }
Dees_Troya58bead2012-09-27 09:49:29 -0400340
Dees_Troy2673cec2013-04-02 20:22:16 +0000341 sync();
342}
343
344void TWFunc::Update_Intent_File(string Intent) {
345 if (PartitionManager.Mount_By_Path("/cache", false) && !Intent.empty()) {
346 TWFunc::write_file("/cache/recovery/intent", Intent);
347 }
Dees_Troya58bead2012-09-27 09:49:29 -0400348}
349
350// reboot: Reboot the system. Return -1 on error, no return on success
351int TWFunc::tw_reboot(RebootCommand command)
352{
353 // Always force a sync before we reboot
Dees_Troy6ef66352013-02-21 08:26:57 -0600354 sync();
Dees_Troya58bead2012-09-27 09:49:29 -0400355
Dees_Troy2673cec2013-04-02 20:22:16 +0000356 switch (command) {
357 case rb_current:
358 case rb_system:
359 Update_Log_File();
360 Update_Intent_File("s");
361 sync();
362 check_and_run_script("/sbin/rebootsystem.sh", "reboot system");
363 return reboot(RB_AUTOBOOT);
364 case rb_recovery:
365 check_and_run_script("/sbin/rebootrecovery.sh", "reboot recovery");
366 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "recovery");
367 case rb_bootloader:
368 check_and_run_script("/sbin/rebootbootloader.sh", "reboot bootloader");
369 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "bootloader");
370 case rb_poweroff:
371 check_and_run_script("/sbin/poweroff.sh", "power off");
Dees_Troya4438782013-02-22 18:44:00 +0000372#ifdef ANDROID_RB_POWEROFF
Dees_Troy2673cec2013-04-02 20:22:16 +0000373 android_reboot(ANDROID_RB_POWEROFF, 0, 0);
Dees_Troya4438782013-02-22 18:44:00 +0000374#endif
Dees_Troy2673cec2013-04-02 20:22:16 +0000375 return reboot(RB_POWER_OFF);
376 case rb_download:
377 check_and_run_script("/sbin/rebootdownload.sh", "reboot download");
378 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "download");
379 default:
380 return -1;
Dees_Troy6ef66352013-02-21 08:26:57 -0600381 }
382 return -1;
Dees_Troya58bead2012-09-27 09:49:29 -0400383}
384
385void TWFunc::check_and_run_script(const char* script_file, const char* display_name)
386{
387 // Check for and run startup script if script exists
388 struct stat st;
389 if (stat(script_file, &st) == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000390 gui_print("Running %s script...\n", display_name);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500391 chmod(script_file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
Vojtech Bocek05534202013-09-11 08:11:56 +0200392 TWFunc::Exec_Cmd(script_file);
Dees_Troy2673cec2013-04-02 20:22:16 +0000393 gui_print("\nFinished running %s script.\n", display_name);
Dees_Troya58bead2012-09-27 09:49:29 -0400394 }
Dees_Troy3477d712012-09-27 15:44:01 -0400395}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500396
397int TWFunc::removeDir(const string path, bool skipParent) {
Dees_Troyce675462013-01-09 19:48:21 +0000398 DIR *d = opendir(path.c_str());
399 int r = 0;
400 string new_path;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500401
Dees_Troyce675462013-01-09 19:48:21 +0000402 if (d == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000403 LOGERR("Error opening '%s'\n", path.c_str());
Dees_Troyce675462013-01-09 19:48:21 +0000404 return -1;
405 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500406
Dees_Troyce675462013-01-09 19:48:21 +0000407 if (d) {
408 struct dirent *p;
409 while (!r && (p = readdir(d))) {
Dees_Troyce675462013-01-09 19:48:21 +0000410 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
411 continue;
412 new_path = path + "/";
413 new_path.append(p->d_name);
414 if (p->d_type == DT_DIR) {
415 r = removeDir(new_path, true);
416 if (!r) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500417 if (p->d_type == DT_DIR)
418 r = rmdir(new_path.c_str());
419 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000420 LOGINFO("Unable to removeDir '%s': %s\n", new_path.c_str(), strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500421 }
bigbiff bigbiff98f1f902013-01-19 18:46:13 -0500422 } 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 +0000423 r = unlink(new_path.c_str());
Dees_Troye34c1332013-02-06 19:13:00 +0000424 if (r != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000425 LOGINFO("Unable to unlink '%s: %s'\n", new_path.c_str(), strerror(errno));
Dees_Troye34c1332013-02-06 19:13:00 +0000426 }
Dees_Troyce675462013-01-09 19:48:21 +0000427 }
428 }
429 closedir(d);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500430
431 if (!r) {
432 if (skipParent)
433 return 0;
434 else
435 r = rmdir(path.c_str());
436 }
Dees_Troyce675462013-01-09 19:48:21 +0000437 }
438 return r;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500439}
440
441int TWFunc::copy_file(string src, string dst, int mode) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000442 LOGINFO("Copying file %s to %s\n", src.c_str(), dst.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500443 ifstream srcfile(src.c_str(), ios::binary);
444 ofstream dstfile(dst.c_str(), ios::binary);
445 dstfile << srcfile.rdbuf();
446 srcfile.close();
447 dstfile.close();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500448 if (chmod(dst.c_str(), mode) != 0)
449 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500450 return 0;
451}
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000452
453unsigned int TWFunc::Get_D_Type_From_Stat(string Path) {
454 struct stat st;
455
456 stat(Path.c_str(), &st);
457 if (st.st_mode & S_IFDIR)
458 return DT_DIR;
459 else if (st.st_mode & S_IFBLK)
460 return DT_BLK;
461 else if (st.st_mode & S_IFCHR)
462 return DT_CHR;
463 else if (st.st_mode & S_IFIFO)
464 return DT_FIFO;
465 else if (st.st_mode & S_IFLNK)
466 return DT_LNK;
467 else if (st.st_mode & S_IFREG)
468 return DT_REG;
469 else if (st.st_mode & S_IFSOCK)
470 return DT_SOCK;
471 return DT_UNKNOWN;
Dees_Troye34c1332013-02-06 19:13:00 +0000472}
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500473
474int TWFunc::read_file(string fn, string& results) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200475 ifstream file;
476 file.open(fn.c_str(), ios::in);
477
478 if (file.is_open()) {
479 file >> results;
480 file.close();
481 return 0;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500482 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200483
484 LOGINFO("Cannot find file %s\n", fn.c_str());
485 return -1;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500486}
487
488int TWFunc::read_file(string fn, vector<string>& results) {
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500489 ifstream file;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500490 string line;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500491 file.open(fn.c_str(), ios::in);
492 if (file.is_open()) {
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500493 while (getline(file, line))
494 results.push_back(line);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500495 file.close();
496 return 0;
497 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000498 LOGINFO("Cannot find file %s\n", fn.c_str());
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500499 return -1;
500}
501
502int TWFunc::write_file(string fn, string& line) {
503 FILE *file;
504 file = fopen(fn.c_str(), "w");
505 if (file != NULL) {
506 fwrite(line.c_str(), line.size(), 1, file);
507 fclose(file);
508 return 0;
509 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000510 LOGINFO("Cannot find file %s\n", fn.c_str());
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500511 return -1;
512}
513
Dees_Troy83bd4832013-05-04 12:39:56 +0000514vector<string> TWFunc::split_string(const string &in, char del, bool skip_empty) {
515 vector<string> res;
516
517 if (in.empty() || del == '\0')
518 return res;
519
520 string field;
521 istringstream f(in);
522 if (del == '\n') {
523 while(getline(f, field)) {
524 if (field.empty() && skip_empty)
525 continue;
526 res.push_back(field);
527 }
528 } else {
529 while(getline(f, field, del)) {
530 if (field.empty() && skip_empty)
531 continue;
532 res.push_back(field);
533 }
534 }
535 return res;
536}
537
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500538timespec TWFunc::timespec_diff(timespec& start, timespec& end)
539{
Dees_Troy6ef66352013-02-21 08:26:57 -0600540 timespec temp;
541 if ((end.tv_nsec-start.tv_nsec)<0) {
542 temp.tv_sec = end.tv_sec-start.tv_sec-1;
543 temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
544 } else {
545 temp.tv_sec = end.tv_sec-start.tv_sec;
546 temp.tv_nsec = end.tv_nsec-start.tv_nsec;
547 }
548 return temp;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500549}
550
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200551int TWFunc::drop_caches(void) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600552 string file = "/proc/sys/vm/drop_caches";
553 string value = "3";
554 if (write_file(file, value) != 0)
555 return -1;
556 return 0;
557}
558
559int TWFunc::Check_su_Perms(void) {
560 struct stat st;
561 int ret = 0;
562
563 if (!PartitionManager.Mount_By_Path("/system", false))
564 return 0;
565
566 // Check to ensure that perms are 6755 for all 3 file locations
567 if (stat("/system/bin/su", &st) == 0) {
568 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) {
569 ret = 1;
570 }
571 }
572 if (stat("/system/xbin/su", &st) == 0) {
573 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) {
574 ret += 2;
575 }
576 }
577 if (stat("/system/bin/.ext/.su", &st) == 0) {
578 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) {
579 ret += 4;
580 }
581 }
582 return ret;
583}
584
585bool TWFunc::Fix_su_Perms(void) {
586 if (!PartitionManager.Mount_By_Path("/system", true))
587 return false;
588
589 string file = "/system/bin/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 }
600 file = "/system/xbin/su";
601 if (TWFunc::Path_Exists(file)) {
602 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000603 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600604 return false;
605 }
606 if (tw_chmod(file, "6755") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000607 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600608 return false;
609 }
610 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000611 file = "/system/xbin/daemonsu";
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, "6755") != 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/bin/.ext/.su";
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, "6755") != 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 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000633 file = "/system/etc/install-recovery.sh";
634 if (TWFunc::Path_Exists(file)) {
635 if (chown(file.c_str(), 0, 0) != 0) {
636 LOGERR("Failed to chown '%s'\n", file.c_str());
637 return false;
638 }
639 if (tw_chmod(file, "0755") != 0) {
640 LOGERR("Failed to chmod '%s'\n", file.c_str());
641 return false;
642 }
643 }
644 file = "/system/etc/init.d/99SuperSUDaemon";
645 if (TWFunc::Path_Exists(file)) {
646 if (chown(file.c_str(), 0, 0) != 0) {
647 LOGERR("Failed to chown '%s'\n", file.c_str());
648 return false;
649 }
650 if (tw_chmod(file, "0755") != 0) {
651 LOGERR("Failed to chmod '%s'\n", file.c_str());
652 return false;
653 }
654 }
Dees_Troy6ef66352013-02-21 08:26:57 -0600655 file = "/system/app/Superuser.apk";
656 if (TWFunc::Path_Exists(file)) {
657 if (chown(file.c_str(), 0, 0) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000658 LOGERR("Failed to chown '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600659 return false;
660 }
661 if (tw_chmod(file, "0644") != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000662 LOGERR("Failed to chmod '%s'\n", file.c_str());
Dees_Troy6ef66352013-02-21 08:26:57 -0600663 return false;
664 }
665 }
666 sync();
667 if (!PartitionManager.UnMount_By_Path("/system", true))
668 return false;
669 return true;
670}
671
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200672int TWFunc::tw_chmod(const string& fn, const string& mode) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600673 long mask = 0;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200674 std::string::size_type n = mode.length();
675 int cls = 0;
Dees_Troy6ef66352013-02-21 08:26:57 -0600676
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200677 if(n == 3)
678 ++cls;
679 else if(n != 4)
680 {
681 LOGERR("TWFunc::tw_chmod used with %u long mode string (should be 3 or 4)!\n", mode.length());
682 return -1;
683 }
684
685 for (n = 0; n < mode.length(); ++n, ++cls) {
686 if (cls == 0) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600687 if (mode[n] == '0')
688 continue;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200689 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600690 mask |= S_ISVTX;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200691 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600692 mask |= S_ISGID;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200693 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600694 mask |= S_ISUID;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200695 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600696 mask |= S_ISVTX;
697 mask |= S_ISUID;
698 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200699 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600700 mask |= S_ISGID;
701 mask |= S_ISUID;
702 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200703 else if (mode[n] == '7') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600704 mask |= S_ISVTX;
705 mask |= S_ISGID;
706 mask |= S_ISUID;
707 }
708 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200709 else if (cls == 1) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600710 if (mode[n] == '7') {
711 mask |= S_IRWXU;
712 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200713 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600714 mask |= S_IRUSR;
715 mask |= S_IWUSR;
716 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200717 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600718 mask |= S_IRUSR;
719 mask |= S_IXUSR;
720 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200721 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600722 mask |= S_IRUSR;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200723 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600724 mask |= S_IWUSR;
725 mask |= S_IRUSR;
726 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200727 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600728 mask |= S_IWUSR;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200729 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600730 mask |= S_IXUSR;
731 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200732 else if (cls == 2) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600733 if (mode[n] == '7') {
734 mask |= S_IRWXG;
735 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200736 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600737 mask |= S_IRGRP;
738 mask |= S_IWGRP;
739 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200740 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600741 mask |= S_IRGRP;
742 mask |= S_IXGRP;
743 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200744 else if (mode[n] == '4')
Dees_Troy6ef66352013-02-21 08:26:57 -0600745 mask |= S_IRGRP;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200746 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600747 mask |= S_IWGRP;
748 mask |= S_IXGRP;
749 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200750 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600751 mask |= S_IWGRP;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200752 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600753 mask |= S_IXGRP;
754 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200755 else if (cls == 3) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600756 if (mode[n] == '7') {
757 mask |= S_IRWXO;
758 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200759 else if (mode[n] == '6') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600760 mask |= S_IROTH;
761 mask |= S_IWOTH;
762 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200763 else if (mode[n] == '5') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600764 mask |= S_IROTH;
765 mask |= S_IXOTH;
766 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200767 else if (mode[n] == '4')
768 mask |= S_IROTH;
769 else if (mode[n] == '3') {
Dees_Troy6ef66352013-02-21 08:26:57 -0600770 mask |= S_IWOTH;
771 mask |= S_IXOTH;
772 }
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200773 else if (mode[n] == '2')
Dees_Troy6ef66352013-02-21 08:26:57 -0600774 mask |= S_IWOTH;
Vojtech Bocek37aeb8d2013-08-29 22:38:20 +0200775 else if (mode[n] == '1')
Dees_Troy6ef66352013-02-21 08:26:57 -0600776 mask |= S_IXOTH;
777 }
778 }
779
780 if (chmod(fn.c_str(), mask) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000781 LOGERR("Unable to chmod '%s' %l\n", fn.c_str(), mask);
Dees_Troy6ef66352013-02-21 08:26:57 -0600782 return -1;
783 }
784
785 return 0;
786}
787
788bool TWFunc::Install_SuperSU(void) {
789 if (!PartitionManager.Mount_By_Path("/system", true))
790 return false;
791
Vojtech Bocek05534202013-09-11 08:11:56 +0200792 TWFunc::Exec_Cmd("/sbin/chattr -i /system/xbin/su");
jt1134113ee732013-02-22 23:26:10 -0600793 if (copy_file("/supersu/su", "/system/xbin/su", 0755) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000794 LOGERR("Failed to copy su binary to /system/bin\n");
Dees_Troy6ef66352013-02-21 08:26:57 -0600795 return false;
796 }
Dees_Troya7939bb2013-08-29 20:21:12 +0000797 if (!Path_Exists("/system/bin/.ext")) {
798 mkdir("/system/bin/.ext", 0777);
799 }
Vojtech Bocek05534202013-09-11 08:11:56 +0200800 TWFunc::Exec_Cmd("/sbin/chattr -i /system/bin/.ext/su");
Dees_Troya7939bb2013-08-29 20:21:12 +0000801 if (copy_file("/supersu/su", "/system/bin/.ext/su", 0755) != 0) {
802 LOGERR("Failed to copy su binary to /system/bin/.ext/su\n");
803 return false;
804 }
Vojtech Bocek05534202013-09-11 08:11:56 +0200805 TWFunc::Exec_Cmd("/sbin/chattr -i /system/xbin/daemonsu");
Dees_Troya7939bb2013-08-29 20:21:12 +0000806 if (copy_file("/supersu/su", "/system/xbin/daemonsu", 0755) != 0) {
807 LOGERR("Failed to copy su binary to /system/xbin/daemonsu\n");
808 return false;
809 }
810 if (Path_Exists("/system/etc/init.d")) {
Vojtech Bocek05534202013-09-11 08:11:56 +0200811 TWFunc::Exec_Cmd("/sbin/chattr -i /system/etc/init.d/99SuperSUDaemon");
Dees_Troya7939bb2013-08-29 20:21:12 +0000812 if (copy_file("/supersu/99SuperSUDaemon", "/system/etc/init.d/99SuperSUDaemon", 0755) != 0) {
813 LOGERR("Failed to copy 99SuperSUDaemon to /system/etc/init.d/99SuperSUDaemon\n");
814 return false;
815 }
816 } else {
Vojtech Bocek05534202013-09-11 08:11:56 +0200817 TWFunc::Exec_Cmd("/sbin/chattr -i /system/etc/install-recovery.sh");
Dees_Troya7939bb2013-08-29 20:21:12 +0000818 if (copy_file("/supersu/install-recovery.sh", "/system/etc/install-recovery.sh", 0755) != 0) {
819 LOGERR("Failed to copy install-recovery.sh to /system/etc/install-recovery.sh\n");
820 return false;
821 }
822 }
jt1134113ee732013-02-22 23:26:10 -0600823 if (copy_file("/supersu/Superuser.apk", "/system/app/Superuser.apk", 0644) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000824 LOGERR("Failed to copy Superuser app to /system/app\n");
Dees_Troy6ef66352013-02-21 08:26:57 -0600825 return false;
826 }
827 if (!Fix_su_Perms())
828 return false;
829 return true;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500830}
Dees_Troy83bd4832013-05-04 12:39:56 +0000831
832int TWFunc::Get_File_Type(string fn) {
833 string::size_type i = 0;
834 int firstbyte = 0, secondbyte = 0;
835 char header[3];
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200836
Dees_Troy83bd4832013-05-04 12:39:56 +0000837 ifstream f;
838 f.open(fn.c_str(), ios::in | ios::binary);
839 f.get(header, 3);
840 f.close();
841 firstbyte = header[i] & 0xff;
842 secondbyte = header[++i] & 0xff;
843
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200844 if (firstbyte == 0x1f && secondbyte == 0x8b)
Dees_Troy83bd4832013-05-04 12:39:56 +0000845 return 1; // Compressed
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200846 else if (firstbyte == 0x4f && secondbyte == 0x41)
Dees_Troy83bd4832013-05-04 12:39:56 +0000847 return 2; // Encrypted
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200848 else
Dees_Troy83bd4832013-05-04 12:39:56 +0000849 return 0; // Unknown
Dees_Troy83bd4832013-05-04 12:39:56 +0000850
851 return 0;
852}
853
854int TWFunc::Try_Decrypting_File(string fn, string password) {
855#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
856 OAES_CTX * ctx = NULL;
857 uint8_t _key_data[32] = "";
858 FILE *f;
859 uint8_t buffer[4096];
860 uint8_t *buffer_out = NULL;
861 uint8_t *ptr = NULL;
862 size_t read_len = 0, out_len = 0;
863 int firstbyte = 0, secondbyte = 0, key_len;
864 size_t _j = 0;
865 size_t _key_data_len = 0;
866
867 // mostly kanged from OpenAES oaes.c
868 for( _j = 0; _j < 32; _j++ )
869 _key_data[_j] = _j + 1;
870 _key_data_len = password.size();
871 if( 16 >= _key_data_len )
872 _key_data_len = 16;
873 else if( 24 >= _key_data_len )
874 _key_data_len = 24;
875 else
876 _key_data_len = 32;
877 memcpy(_key_data, password.c_str(), password.size());
878
879 ctx = oaes_alloc();
880 if (ctx == NULL) {
881 LOGERR("Failed to allocate OAES\n");
882 return -1;
883 }
884
885 oaes_key_import_data(ctx, _key_data, _key_data_len);
886
887 f = fopen(fn.c_str(), "rb");
888 if (f == NULL) {
889 LOGERR("Failed to open '%s' to try decrypt\n", fn.c_str());
890 return -1;
891 }
892 read_len = fread(buffer, sizeof(uint8_t), 4096, f);
893 if (read_len <= 0) {
894 LOGERR("Read size during try decrypt failed\n");
895 fclose(f);
896 return -1;
897 }
898 if (oaes_decrypt(ctx, buffer, read_len, NULL, &out_len) != OAES_RET_SUCCESS) {
899 LOGERR("Error: Failed to retrieve required buffer size for trying decryption.\n");
900 fclose(f);
901 return -1;
902 }
903 buffer_out = (uint8_t *) calloc(out_len, sizeof(char));
904 if (buffer_out == NULL) {
905 LOGERR("Failed to allocate output buffer for try decrypt.\n");
906 fclose(f);
907 return -1;
908 }
909 if (oaes_decrypt(ctx, buffer, read_len, buffer_out, &out_len) != OAES_RET_SUCCESS) {
910 LOGERR("Failed to decrypt file '%s'\n", fn.c_str());
911 fclose(f);
912 free(buffer_out);
913 return 0;
914 }
915 fclose(f);
916 if (out_len < 2) {
917 LOGINFO("Successfully decrypted '%s' but read length %i too small.\n", fn.c_str(), out_len);
918 free(buffer_out);
919 return 1; // Decrypted successfully
920 }
921 ptr = buffer_out;
922 firstbyte = *ptr & 0xff;
923 ptr++;
924 secondbyte = *ptr & 0xff;
925 if (firstbyte == 0x1f && secondbyte == 0x8b) {
926 LOGINFO("Successfully decrypted '%s' and file is compressed.\n", fn.c_str());
927 free(buffer_out);
928 return 3; // Compressed
929 }
930 if (out_len >= 262) {
931 ptr = buffer_out + 257;
932 if (strncmp((char*)ptr, "ustar", 5) == 0) {
933 LOGINFO("Successfully decrypted '%s' and file is tar format.\n", fn.c_str());
934 free(buffer_out);
935 return 2; // Tar
936 }
937 }
938 free(buffer_out);
939 LOGINFO("No errors decrypting '%s' but no known file format.\n", fn.c_str());
940 return 1; // Decrypted successfully
941#else
942 LOGERR("Encrypted backup support not included.\n");
943 return -1;
944#endif
945}
946
947bool TWFunc::Try_Decrypting_Backup(string Restore_Path, string Password) {
948 DIR* d;
949
950 string Filename;
951 Restore_Path += "/";
952 d = opendir(Restore_Path.c_str());
953 if (d == NULL) {
954 LOGERR("Error opening '%s'\n", Restore_Path.c_str());
955 return false;
956 }
957
958 struct dirent* de;
959 while ((de = readdir(d)) != NULL) {
960 Filename = Restore_Path;
961 Filename += de->d_name;
962 if (TWFunc::Get_File_Type(Filename) == 2) {
963 if (TWFunc::Try_Decrypting_File(Filename, Password) < 2) {
964 DataManager::SetValue("tw_restore_password", ""); // Clear the bad password
965 DataManager::SetValue("tw_restore_display", ""); // Also clear the display mask
966 closedir(d);
967 return false;
968 }
969 }
970 }
971 closedir(d);
972 return true;
973}
974
975int TWFunc::Wait_For_Child(pid_t pid, int *status, string Child_Name) {
976 pid_t rc_pid;
977
978 rc_pid = waitpid(pid, status, 0);
979 if (rc_pid > 0) {
980 if (WEXITSTATUS(*status) == 0)
981 LOGINFO("%s process ended with RC=%d\n", Child_Name.c_str(), WEXITSTATUS(*status)); // Success
982 else if (WIFSIGNALED(*status)) {
983 LOGINFO("%s process ended with signal: %d\n", Child_Name.c_str(), WTERMSIG(*status)); // Seg fault or some other non-graceful termination
984 return -1;
985 } else if (WEXITSTATUS(*status) != 0) {
986 LOGINFO("%s process ended with ERROR=%d\n", Child_Name.c_str(), WEXITSTATUS(*status)); // Graceful exit, but there was an error
987 return -1;
988 }
989 } else { // no PID returned
990 if (errno == ECHILD)
991 LOGINFO("%s no child process exist\n", Child_Name.c_str());
992 else {
993 LOGINFO("%s Unexpected error\n", Child_Name.c_str());
994 return -1;
995 }
996 }
997 return 0;
998}
Dees Troyb21cc642013-09-10 17:36:41 +0000999
1000string TWFunc::Get_Current_Date() {
1001 string Current_Date;
1002 time_t seconds = time(0);
1003 struct tm *t = localtime(&seconds);
1004 char timestamp[255];
1005 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);
1006 Current_Date = timestamp;
1007 return Current_Date;
1008}
1009
1010void TWFunc::Auto_Generate_Backup_Name() {
1011 bool mount_state = PartitionManager.Is_Mounted_By_Path("/system");
1012 std::vector<string> buildprop;
1013 if (!PartitionManager.Mount_By_Path("/system", true)) {
1014 DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
1015 return;
1016 }
1017 if (TWFunc::read_file("/system/build.prop", buildprop) != 0) {
1018 LOGINFO("Unable to open /system/build.prop for getting backup name.\n");
Vojtech Boceka2e70162013-09-17 17:05:10 +02001019 DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
Dees Troyb21cc642013-09-10 17:36:41 +00001020 if (!mount_state)
1021 PartitionManager.UnMount_By_Path("/system", false);
1022 return;
1023 }
1024 int line_count = buildprop.size();
1025 int index;
1026 size_t start_pos = 0, end_pos;
1027 string propname, propvalue;
1028 for (index = 0; index < line_count; index++) {
1029 end_pos = buildprop.at(index).find("=", start_pos);
1030 propname = buildprop.at(index).substr(start_pos, end_pos);
1031 if (propname == "ro.build.display.id") {
1032 propvalue = buildprop.at(index).substr(end_pos + 1, buildprop.at(index).size());
1033 string Backup_Name = Get_Current_Date();
1034 Backup_Name += " " + propvalue;
1035 if (Backup_Name.size() > MAX_BACKUP_NAME_LEN)
1036 Backup_Name.resize(MAX_BACKUP_NAME_LEN);
Dees Troya829d5d2013-10-17 00:26:23 +00001037 // Trailing spaces cause problems on some file systems, so remove them
1038 string space_check, space = " ";
1039 space_check = Backup_Name.substr(Backup_Name.size() - 1, 1);
1040 while (space_check == space) {
1041 Backup_Name.resize(Backup_Name.size() - 1);
1042 space_check = Backup_Name.substr(Backup_Name.size() - 1, 1);
1043 }
Dees Troyb21cc642013-09-10 17:36:41 +00001044 DataManager::SetValue(TW_BACKUP_NAME, Backup_Name);
1045 break;
1046 }
1047 }
1048 if (propvalue.empty()) {
1049 LOGINFO("ro.build.display.id not found in build.prop\n");
Vojtech Boceka2e70162013-09-17 17:05:10 +02001050 DataManager::SetValue(TW_BACKUP_NAME, Get_Current_Date());
Dees Troyb21cc642013-09-10 17:36:41 +00001051 }
1052 if (!mount_state)
1053 PartitionManager.UnMount_By_Path("/system", false);
Vojtech Bocek05534202013-09-11 08:11:56 +02001054}