blob: a90be5a6dfba98529cf4d67841d0b1c7ffec8ba6 [file] [log] [blame]
Dees_Troy38bd7602012-09-14 13:33:53 -04001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
Dees_Troy38bd7602012-09-14 13:33:53 -04004#include <unistd.h>
5#include <vector>
6#include <dirent.h>
7#include <time.h>
Dees_Troy43d8b002012-09-17 16:00:01 -04008#include <errno.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -05009#include <fcntl.h>
10#include <sys/mount.h>
Dees_Troya58bead2012-09-27 09:49:29 -040011#include <sys/reboot.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050012#include <sys/sendfile.h>
13#include <sys/stat.h>
14#include <sys/vfs.h>
Dees_Troya4438782013-02-22 18:44:00 +000015#ifdef ANDROID_RB_POWEROFF
16 #include "cutils/android_reboot.h"
17#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050018#include <iostream>
19#include <fstream>
Dees_Troy38bd7602012-09-14 13:33:53 -040020#include "twrp-functions.hpp"
21#include "partitions.hpp"
22#include "common.h"
Dees_Troyb46a6842012-09-25 11:06:46 -040023#include "data.hpp"
Dees_Troya58bead2012-09-27 09:49:29 -040024#include "bootloader.h"
Dees_Troy3477d712012-09-27 15:44:01 -040025#include "variables.h"
Dees_Troy38bd7602012-09-14 13:33:53 -040026
Dees_Troyb05ddee2013-01-28 20:24:50 +000027extern "C" {
28 #include "libcrecovery/common.h"
29}
30
bigbiff bigbiff9c754052013-01-09 09:09:08 -050031
32/* Execute a command */
33
34int TWFunc::Exec_Cmd(string cmd, string &result) {
35 FILE* exec;
Dees_Troyb05ddee2013-01-28 20:24:50 +000036 char buffer[130];
bigbiff bigbiff9c754052013-01-09 09:09:08 -050037 int ret = 0;
Dees_Troyb05ddee2013-01-28 20:24:50 +000038 exec = __popen(cmd.c_str(), "r");
bigbiff bigbiff9c754052013-01-09 09:09:08 -050039 if (!exec) return -1;
40 while(!feof(exec)) {
Dees_Troyb05ddee2013-01-28 20:24:50 +000041 memset(&buffer, 0, sizeof(buffer));
42 if (fgets(buffer, 128, exec) != NULL) {
43 buffer[128] = '\n';
44 buffer[129] = NULL;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050045 result += buffer;
Dees_Troyb05ddee2013-01-28 20:24:50 +000046 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -050047 }
Dees_Troyb05ddee2013-01-28 20:24:50 +000048 ret = __pclose(exec);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050049 return ret;
50}
51
Dees_Troy38bd7602012-09-14 13:33:53 -040052/* Checks md5 for a path
Dees_Troy6ef66352013-02-21 08:26:57 -060053 Return values:
54 -1 : MD5 does not exist
55 0 : Failed
56 1 : Success */
Dees_Troy38bd7602012-09-14 13:33:53 -040057int TWFunc::Check_MD5(string File) {
58 int ret;
59 string Command, DirPath, MD5_File, Sline, Filename, MD5_File_Filename, OK;
60 char line[255];
61 size_t pos;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050062 string result;
Dees_Troy38bd7602012-09-14 13:33:53 -040063
64 MD5_File = File + ".md5";
Dees_Troy2a923582012-09-20 12:13:34 -040065 if (Path_Exists(MD5_File)) {
Dees_Troy38bd7602012-09-14 13:33:53 -040066 DirPath = Get_Path(File);
Dees_Troy38bd7602012-09-14 13:33:53 -040067 MD5_File = Get_Filename(MD5_File);
Dees_Troy3f5c4e82013-02-01 15:16:59 +000068 Command = "cd '" + DirPath + "' && /sbin/busybox md5sum -c '" + MD5_File + "'";
bigbiff bigbiff9c754052013-01-09 09:09:08 -050069 Exec_Cmd(Command, result);
70 pos = result.find(":");
Dees_Troy38bd7602012-09-14 13:33:53 -040071 if (pos != string::npos) {
72 Filename = Get_Filename(File);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050073 MD5_File_Filename = result.substr(0, pos);
74 OK = result.substr(pos + 2, result.size() - pos - 2);
Dees_Troy38bd7602012-09-14 13:33:53 -040075 if (Filename == MD5_File_Filename && (OK == "OK" || OK == "OK\n")) {
76 //MD5 is good, return 1
77 ret = 1;
78 } else {
79 // MD5 is bad, return 0
80 ret = 0;
81 }
82 } else {
83 // MD5 is bad, return 0
84 ret = 0;
85 }
Dees_Troy38bd7602012-09-14 13:33:53 -040086 } else {
87 //No md5 file, return -1
88 ret = -1;
89 }
90
Dees_Troy6ef66352013-02-21 08:26:57 -060091 return ret;
Dees_Troy38bd7602012-09-14 13:33:53 -040092}
93
94// Returns "file.name" from a full /path/to/file.name
95string TWFunc::Get_Filename(string Path) {
96 size_t pos = Path.find_last_of("/");
97 if (pos != string::npos) {
98 string Filename;
99 Filename = Path.substr(pos + 1, Path.size() - pos - 1);
100 return Filename;
101 } else
102 return Path;
103}
104
105// Returns "/path/to/" from a full /path/to/file.name
106string TWFunc::Get_Path(string Path) {
107 size_t pos = Path.find_last_of("/");
108 if (pos != string::npos) {
109 string Pathonly;
110 Pathonly = Path.substr(0, pos + 1);
111 return Pathonly;
112 } else
113 return Path;
114}
115
116// Returns "/path" from a full /path/to/file.name
117string TWFunc::Get_Root_Path(string Path) {
118 string Local_Path = Path;
119
120 // Make sure that we have a leading slash
121 if (Local_Path.substr(0, 1) != "/")
122 Local_Path = "/" + Local_Path;
123
124 // Trim the path to get the root path only
125 size_t position = Local_Path.find("/", 2);
126 if (position != string::npos) {
127 Local_Path.resize(position);
128 }
129 return Local_Path;
130}
131
132void TWFunc::install_htc_dumlock(void) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400133 int need_libs = 0;
134
135 if (!PartitionManager.Mount_By_Path("/system", true))
136 return;
137
138 if (!PartitionManager.Mount_By_Path("/data", true))
139 return;
140
141 ui_print("Installing HTC Dumlock to system...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500142 copy_file("/res/htcd/htcdumlocksys", "/system/bin/htcdumlock", 0755);
Dees_Troy8170a922012-09-18 15:40:25 -0400143 if (!Path_Exists("/system/bin/flash_image")) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400144 ui_print("Installing flash_image...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500145 copy_file("/res/htcd/flash_imagesys", "/system/bin/flash_image", 0755);
Dees_Troy38bd7602012-09-14 13:33:53 -0400146 need_libs = 1;
147 } else
148 ui_print("flash_image is already installed, skipping...\n");
Dees_Troy8170a922012-09-18 15:40:25 -0400149 if (!Path_Exists("/system/bin/dump_image")) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400150 ui_print("Installing dump_image...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500151 copy_file("/res/htcd/dump_imagesys", "/system/bin/dump_image", 0755);
Dees_Troy38bd7602012-09-14 13:33:53 -0400152 need_libs = 1;
153 } else
154 ui_print("dump_image is already installed, skipping...\n");
155 if (need_libs) {
156 ui_print("Installing libs needed for flash_image and dump_image...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500157 copy_file("/res/htcd/libbmlutils.so", "/system/lib/libbmlutils.so", 0755);
158 copy_file("/res/htcd/libflashutils.so", "/system/lib/libflashutils.so", 0755);
159 copy_file("/res/htcd/libmmcutils.so", "/system/lib/libmmcutils.so", 0755);
160 copy_file("/res/htcd/libmtdutils.so", "/system/lib/libmtdutils.so", 0755);
Dees_Troy38bd7602012-09-14 13:33:53 -0400161 }
162 ui_print("Installing HTC Dumlock app...\n");
163 mkdir("/data/app", 0777);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500164 unlink("/data/app/com.teamwin.htcdumlock*");
165 copy_file("/res/htcd/HTCDumlock.apk", "/data/app/com.teamwin.htcdumlock.apk", 0777);
Dees_Troy38bd7602012-09-14 13:33:53 -0400166 sync();
167 ui_print("HTC Dumlock is installed.\n");
168}
169
170void TWFunc::htc_dumlock_restore_original_boot(void) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500171 string status;
Dees_Troy38bd7602012-09-14 13:33:53 -0400172 if (!PartitionManager.Mount_By_Path("/sdcard", true))
173 return;
174
175 ui_print("Restoring original boot...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500176 Exec_Cmd("htcdumlock restore", status);
Dees_Troy38bd7602012-09-14 13:33:53 -0400177 ui_print("Original boot restored.\n");
178}
179
180void TWFunc::htc_dumlock_reflash_recovery_to_boot(void) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500181 string status;
Dees_Troy38bd7602012-09-14 13:33:53 -0400182 if (!PartitionManager.Mount_By_Path("/sdcard", true))
183 return;
Dees_Troy38bd7602012-09-14 13:33:53 -0400184 ui_print("Reflashing recovery to boot...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500185 Exec_Cmd("htcdumlock recovery noreboot", status);
Dees_Troy38bd7602012-09-14 13:33:53 -0400186 ui_print("Recovery is flashed to boot.\n");
187}
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) {
198 LOGE("Unable to create folder: %s (errno=%d)\n", wholePath.c_str(), errno);
199 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 {
Vojtech Bocek2e97ec52013-02-02 13:22:42 +0100219 LOGE("error opening '%s'\n", Path.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500220 LOGE("error: %s\n", strerror(errno));
Dees_Troy43d8b002012-09-17 16:00:01 -0400221 return 0;
222 }
223
224 while ((de = readdir(d)) != NULL)
225 {
226 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
227 {
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
281static const char *COMMAND_FILE = "/cache/recovery/command";
282static const char *INTENT_FILE = "/cache/recovery/intent";
283static const char *LOG_FILE = "/cache/recovery/log";
284static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
285static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
286static const char *CACHE_ROOT = "/cache";
287static const char *SDCARD_ROOT = "/sdcard";
288static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
289static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
290
291// close a file, log an error if the error indicator is set
292void TWFunc::check_and_fclose(FILE *fp, const char *name) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600293 fflush(fp);
294 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
295 fclose(fp);
Dees_Troya58bead2012-09-27 09:49:29 -0400296}
297
298void TWFunc::copy_log_file(const char* source, const char* destination, int append) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600299 FILE *log = fopen_path(destination, append ? "a" : "w");
300 if (log == NULL) {
301 LOGE("Can't open %s\n", destination);
302 } else {
303 FILE *tmplog = fopen(source, "r");
304 if (tmplog != NULL) {
305 if (append) {
306 fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write
307 }
308 char buf[4096];
309 while (fgets(buf, sizeof(buf), tmplog)) fputs(buf, log);
310 if (append) {
311 tmplog_offset = ftell(tmplog);
312 }
313 check_and_fclose(tmplog, source);
314 }
315 check_and_fclose(log, destination);
316 }
Dees_Troya58bead2012-09-27 09:49:29 -0400317}
318
319// clear the recovery command and prepare to boot a (hopefully working) system,
320// copy our log file to cache as well (for the system to read), and
321// record any intent we were asked to communicate back to the system.
322// this function is idempotent: call it as many times as you like.
323void TWFunc::twfinish_recovery(const char *send_intent) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500324 // By this point, we're ready to return to the main system...
325 if (send_intent != NULL) {
326 FILE *fp = fopen_path(INTENT_FILE, "w");
327 if (fp == NULL) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600328 LOGE("Can't open %s\n", INTENT_FILE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500329 } else {
Dees_Troy6ef66352013-02-21 08:26:57 -0600330 fputs(send_intent, fp);
331 check_and_fclose(fp, INTENT_FILE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500332 }
333 }
Dees_Troya58bead2012-09-27 09:49:29 -0400334
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500335 // Copy logs to cache so the system can find out what happened.
336 copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
337 copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
338 copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
339 chmod(LOG_FILE, 0600);
340 chown(LOG_FILE, 1000, 1000); // system user
341 chmod(LAST_LOG_FILE, 0640);
342 chmod(LAST_INSTALL_FILE, 0644);
Dees_Troya58bead2012-09-27 09:49:29 -0400343
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500344 // Reset to normal system boot so recovery won't cycle indefinitely.
345 struct bootloader_message boot;
346 memset(&boot, 0, sizeof(boot));
347 set_bootloader_message(&boot);
Dees_Troya58bead2012-09-27 09:49:29 -0400348
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500349 // Remove the command file, so recovery won't repeat indefinitely.
350 if (!PartitionManager.Mount_By_Path("/system", true) || (unlink(COMMAND_FILE) && errno != ENOENT)) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600351 LOGW("Can't unlink %s\n", COMMAND_FILE);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500352 }
Dees_Troya58bead2012-09-27 09:49:29 -0400353
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500354 PartitionManager.UnMount_By_Path("/cache", true);
355 sync(); // For good measure.
Dees_Troya58bead2012-09-27 09:49:29 -0400356}
357
358// reboot: Reboot the system. Return -1 on error, no return on success
359int TWFunc::tw_reboot(RebootCommand command)
360{
361 // Always force a sync before we reboot
Dees_Troy6ef66352013-02-21 08:26:57 -0600362 sync();
Dees_Troya58bead2012-09-27 09:49:29 -0400363
Dees_Troy6ef66352013-02-21 08:26:57 -0600364 switch (command)
365 {
366 case rb_current:
367 case rb_system:
368 twfinish_recovery("s");
Dees_Troya58bead2012-09-27 09:49:29 -0400369 sync();
370 check_and_run_script("/sbin/rebootsystem.sh", "reboot system");
Dees_Troy6ef66352013-02-21 08:26:57 -0600371 return reboot(RB_AUTOBOOT);
372 case rb_recovery:
Dees_Troya58bead2012-09-27 09:49:29 -0400373 check_and_run_script("/sbin/rebootrecovery.sh", "reboot recovery");
Dees_Troy6ef66352013-02-21 08:26:57 -0600374 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "recovery");
375 case rb_bootloader:
Dees_Troya58bead2012-09-27 09:49:29 -0400376 check_and_run_script("/sbin/rebootbootloader.sh", "reboot bootloader");
Dees_Troy6ef66352013-02-21 08:26:57 -0600377 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "bootloader");
378 case rb_poweroff:
Dees_Troya58bead2012-09-27 09:49:29 -0400379 check_and_run_script("/sbin/poweroff.sh", "power off");
Dees_Troya4438782013-02-22 18:44:00 +0000380#ifdef ANDROID_RB_POWEROFF
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500381 android_reboot(ANDROID_RB_POWEROFF, 0, 0);
Dees_Troya4438782013-02-22 18:44:00 +0000382#endif
Dees_Troy6ef66352013-02-21 08:26:57 -0600383 return reboot(RB_POWER_OFF);
384 case rb_download:
Dees_Troya58bead2012-09-27 09:49:29 -0400385 check_and_run_script("/sbin/rebootdownload.sh", "reboot download");
386 return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, (void*) "download");
387 return 1;
Dees_Troy6ef66352013-02-21 08:26:57 -0600388 default:
389 return -1;
390 }
391 return -1;
Dees_Troya58bead2012-09-27 09:49:29 -0400392}
393
394void TWFunc::check_and_run_script(const char* script_file, const char* display_name)
395{
396 // Check for and run startup script if script exists
397 struct stat st;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500398 string result;
Dees_Troya58bead2012-09-27 09:49:29 -0400399 if (stat(script_file, &st) == 0) {
400 ui_print("Running %s script...\n", display_name);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500401 chmod(script_file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
402 TWFunc::Exec_Cmd(script_file, result);
Dees_Troya58bead2012-09-27 09:49:29 -0400403 ui_print("\nFinished running %s script.\n", display_name);
404 }
Dees_Troy3477d712012-09-27 15:44:01 -0400405}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500406
407int TWFunc::removeDir(const string path, bool skipParent) {
Dees_Troyce675462013-01-09 19:48:21 +0000408 DIR *d = opendir(path.c_str());
409 int r = 0;
410 string new_path;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500411
Dees_Troyce675462013-01-09 19:48:21 +0000412 if (d == NULL) {
413 LOGE("Error opening '%s'\n", path.c_str());
414 return -1;
415 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500416
Dees_Troyce675462013-01-09 19:48:21 +0000417 if (d) {
418 struct dirent *p;
419 while (!r && (p = readdir(d))) {
Dees_Troyce675462013-01-09 19:48:21 +0000420 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
421 continue;
422 new_path = path + "/";
423 new_path.append(p->d_name);
424 if (p->d_type == DT_DIR) {
425 r = removeDir(new_path, true);
426 if (!r) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500427 if (p->d_type == DT_DIR)
428 r = rmdir(new_path.c_str());
429 else
430 LOGI("Unable to removeDir '%s': %s\n", new_path.c_str(), strerror(errno));
431 }
bigbiff bigbiff98f1f902013-01-19 18:46:13 -0500432 } 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 +0000433 r = unlink(new_path.c_str());
Dees_Troye34c1332013-02-06 19:13:00 +0000434 if (r != 0) {
435 LOGI("Unable to unlink '%s: %s'\n", new_path.c_str(), strerror(errno));
436 }
Dees_Troyce675462013-01-09 19:48:21 +0000437 }
438 }
439 closedir(d);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500440
441 if (!r) {
442 if (skipParent)
443 return 0;
444 else
445 r = rmdir(path.c_str());
446 }
Dees_Troyce675462013-01-09 19:48:21 +0000447 }
448 return r;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500449}
450
451int TWFunc::copy_file(string src, string dst, int mode) {
452 LOGI("Copying file %s to %s\n", src.c_str(), dst.c_str());
453 ifstream srcfile(src.c_str(), ios::binary);
454 ofstream dstfile(dst.c_str(), ios::binary);
455 dstfile << srcfile.rdbuf();
456 srcfile.close();
457 dstfile.close();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500458 if (chmod(dst.c_str(), mode) != 0)
459 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500460 return 0;
461}
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000462
463unsigned int TWFunc::Get_D_Type_From_Stat(string Path) {
464 struct stat st;
465
466 stat(Path.c_str(), &st);
467 if (st.st_mode & S_IFDIR)
468 return DT_DIR;
469 else if (st.st_mode & S_IFBLK)
470 return DT_BLK;
471 else if (st.st_mode & S_IFCHR)
472 return DT_CHR;
473 else if (st.st_mode & S_IFIFO)
474 return DT_FIFO;
475 else if (st.st_mode & S_IFLNK)
476 return DT_LNK;
477 else if (st.st_mode & S_IFREG)
478 return DT_REG;
479 else if (st.st_mode & S_IFSOCK)
480 return DT_SOCK;
481 return DT_UNKNOWN;
Dees_Troye34c1332013-02-06 19:13:00 +0000482}
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500483
484int TWFunc::read_file(string fn, string& results) {
485 ifstream file;
486 file.open(fn.c_str(), ios::in);
487 if (file.is_open()) {
488 file >> results;
489 file.close();
490 return 0;
491 }
492 LOGI("Cannot find file %s\n", fn.c_str());
493 return -1;
494}
495
496int TWFunc::write_file(string fn, string& line) {
497 FILE *file;
498 file = fopen(fn.c_str(), "w");
499 if (file != NULL) {
500 fwrite(line.c_str(), line.size(), 1, file);
501 fclose(file);
502 return 0;
503 }
504 LOGI("Cannot find file %s\n", fn.c_str());
505 return -1;
506}
507
508timespec TWFunc::timespec_diff(timespec& start, timespec& end)
509{
Dees_Troy6ef66352013-02-21 08:26:57 -0600510 timespec temp;
511 if ((end.tv_nsec-start.tv_nsec)<0) {
512 temp.tv_sec = end.tv_sec-start.tv_sec-1;
513 temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
514 } else {
515 temp.tv_sec = end.tv_sec-start.tv_sec;
516 temp.tv_nsec = end.tv_nsec-start.tv_nsec;
517 }
518 return temp;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500519}
520
521 int TWFunc::drop_caches(void) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600522 string file = "/proc/sys/vm/drop_caches";
523 string value = "3";
524 if (write_file(file, value) != 0)
525 return -1;
526 return 0;
527}
528
529int TWFunc::Check_su_Perms(void) {
530 struct stat st;
531 int ret = 0;
532
533 if (!PartitionManager.Mount_By_Path("/system", false))
534 return 0;
535
536 // Check to ensure that perms are 6755 for all 3 file locations
537 if (stat("/system/bin/su", &st) == 0) {
538 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) {
539 ret = 1;
540 }
541 }
542 if (stat("/system/xbin/su", &st) == 0) {
543 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) {
544 ret += 2;
545 }
546 }
547 if (stat("/system/bin/.ext/.su", &st) == 0) {
548 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) {
549 ret += 4;
550 }
551 }
552 return ret;
553}
554
555bool TWFunc::Fix_su_Perms(void) {
556 if (!PartitionManager.Mount_By_Path("/system", true))
557 return false;
558
559 string file = "/system/bin/su";
560 if (TWFunc::Path_Exists(file)) {
561 if (chown(file.c_str(), 0, 0) != 0) {
562 LOGE("Failed to chown '%s'\n", file.c_str());
563 return false;
564 }
565 if (tw_chmod(file, "6755") != 0) {
566 LOGE("Failed to chmod '%s'\n", file.c_str());
567 return false;
568 }
569 }
570 file = "/system/xbin/su";
571 if (TWFunc::Path_Exists(file)) {
572 if (chown(file.c_str(), 0, 0) != 0) {
573 LOGE("Failed to chown '%s'\n", file.c_str());
574 return false;
575 }
576 if (tw_chmod(file, "6755") != 0) {
577 LOGE("Failed to chmod '%s'\n", file.c_str());
578 return false;
579 }
580 }
581 file = "/system/bin/.ext/.su";
582 if (TWFunc::Path_Exists(file)) {
583 if (chown(file.c_str(), 0, 0) != 0) {
584 LOGE("Failed to chown '%s'\n", file.c_str());
585 return false;
586 }
587 if (tw_chmod(file, "6755") != 0) {
588 LOGE("Failed to chmod '%s'\n", file.c_str());
589 return false;
590 }
591 }
592 file = "/system/app/Superuser.apk";
593 if (TWFunc::Path_Exists(file)) {
594 if (chown(file.c_str(), 0, 0) != 0) {
595 LOGE("Failed to chown '%s'\n", file.c_str());
596 return false;
597 }
598 if (tw_chmod(file, "0644") != 0) {
599 LOGE("Failed to chmod '%s'\n", file.c_str());
600 return false;
601 }
602 }
603 sync();
604 if (!PartitionManager.UnMount_By_Path("/system", true))
605 return false;
606 return true;
607}
608
609int TWFunc::tw_chmod(string fn, string mode) {
610 long mask = 0;
611
612 for ( std::string::size_type n = 0; n < mode.length(); ++n) {
613 if (n == 0) {
614 if (mode[n] == '0')
615 continue;
616 if (mode[n] == '1')
617 mask |= S_ISVTX;
618 if (mode[n] == '2')
619 mask |= S_ISGID;
620 if (mode[n] == '4')
621 mask |= S_ISUID;
622 if (mode[n] == '5') {
623 mask |= S_ISVTX;
624 mask |= S_ISUID;
625 }
626 if (mode[n] == '6') {
627 mask |= S_ISGID;
628 mask |= S_ISUID;
629 }
630 if (mode[n] == '7') {
631 mask |= S_ISVTX;
632 mask |= S_ISGID;
633 mask |= S_ISUID;
634 }
635 }
636 else if (n == 1) {
637 if (mode[n] == '7') {
638 mask |= S_IRWXU;
639 }
640 if (mode[n] == '6') {
641 mask |= S_IRUSR;
642 mask |= S_IWUSR;
643 }
644 if (mode[n] == '5') {
645 mask |= S_IRUSR;
646 mask |= S_IXUSR;
647 }
648 if (mode[n] == '4')
649 mask |= S_IRUSR;
650 if (mode[n] == '3') {
651 mask |= S_IWUSR;
652 mask |= S_IRUSR;
653 }
654 if (mode[n] == '2')
655 mask |= S_IWUSR;
656 if (mode[n] == '1')
657 mask |= S_IXUSR;
658 }
659 else if (n == 2) {
660 if (mode[n] == '7') {
661 mask |= S_IRWXG;
662 }
663 if (mode[n] == '6') {
664 mask |= S_IRGRP;
665 mask |= S_IWGRP;
666 }
667 if (mode[n] == '5') {
668 mask |= S_IRGRP;
669 mask |= S_IXGRP;
670 }
671 if (mode[n] == '4')
672 mask |= S_IRGRP;
673 if (mode[n] == '3') {
674 mask |= S_IWGRP;
675 mask |= S_IXGRP;
676 }
677 if (mode[n] == '2')
678 mask |= S_IWGRP;
679 if (mode[n] == '1')
680 mask |= S_IXGRP;
681 }
682 else if (n == 3) {
683 if (mode[n] == '7') {
684 mask |= S_IRWXO;
685 }
686 if (mode[n] == '6') {
687 mask |= S_IROTH;
688 mask |= S_IWOTH;
689 }
690 if (mode[n] == '5') {
691 mask |= S_IROTH;
692 mask |= S_IXOTH;
693 }
694 if (mode[n] == '4')
695 mask |= S_IROTH;
696 if (mode[n] == '3') {
697 mask |= S_IWOTH;
698 mask |= S_IXOTH;
699 }
700 if (mode[n] == '2')
701 mask |= S_IWOTH;
702 if (mode[n] == '1')
703 mask |= S_IXOTH;
704 }
705 }
706
707 if (chmod(fn.c_str(), mask) != 0) {
708 LOGE("Unable to chmod '%s' %l\n", fn.c_str(), mask);
709 return -1;
710 }
711
712 return 0;
713}
714
715bool TWFunc::Install_SuperSU(void) {
716 if (!PartitionManager.Mount_By_Path("/system", true))
717 return false;
718
jt1134113ee732013-02-22 23:26:10 -0600719 if (copy_file("/supersu/su", "/system/xbin/su", 0755) != 0) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600720 LOGE("Failed to copy su binary to /system/bin\n");
721 return false;
722 }
jt1134113ee732013-02-22 23:26:10 -0600723 if (copy_file("/supersu/Superuser.apk", "/system/app/Superuser.apk", 0644) != 0) {
Dees_Troy6ef66352013-02-21 08:26:57 -0600724 LOGE("Failed to copy Superuser app to /system/app\n");
725 return false;
726 }
727 if (!Fix_su_Perms())
728 return false;
729 return true;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500730}