summaryrefslogtreecommitdiffstats
path: root/partitionmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'partitionmanager.cpp')
-rw-r--r--partitionmanager.cpp363
1 files changed, 344 insertions, 19 deletions
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index e896cee2c..0486c7a66 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -22,6 +22,7 @@
#include <sys/stat.h>
#include <sys/vfs.h>
#include <unistd.h>
+#include <map>
#include <vector>
#include <dirent.h>
#include <time.h>
@@ -33,6 +34,12 @@
#include <sys/wait.h>
#include <linux/fs.h>
#include <sys/mount.h>
+
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+
#include "variables.h"
#include "twcommon.h"
#include "partitions.hpp"
@@ -80,6 +87,7 @@ extern bool datamedia;
TWPartitionManager::TWPartitionManager(void) {
mtp_was_enabled = false;
mtp_write_fd = -1;
+ uevent_pfd.fd = -1;
stop_backup.set_value(0);
#ifdef AB_OTA_UPDATER
char slot_suffix[PROPERTY_VALUE_MAX];
@@ -98,22 +106,88 @@ int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error)
TWPartition* settings_partition = NULL;
TWPartition* andsec_partition = NULL;
unsigned int storageid = 1 << 16; // upper 16 bits are for physical storage device, we pretend to have only one
+ std::map<string, Flags_Map> twrp_flags;
+
+ fstabFile = fopen("/etc/twrp.flags", "rt");
+ if (fstabFile != NULL) {
+ LOGINFO("reading /etc/twrp.flags\n");
+ while (fgets(fstab_line, sizeof(fstab_line), fstabFile) != NULL) {
+ if (fstab_line[0] != '/')
+ continue;
+
+ size_t line_size = strlen(fstab_line);
+ if (fstab_line[line_size - 1] != '\n')
+ fstab_line[line_size] = '\n';
+ Flags_Map line_flags;
+ line_flags.Primary_Block_Device = "";
+ line_flags.Alternate_Block_Device = "";
+ line_flags.fstab_line = (char*)malloc(MAX_FSTAB_LINE_LENGTH);
+ if (!line_flags.fstab_line) {
+ LOGERR("malloc error on line_flags.fstab_line\n");
+ return false;
+ }
+ memcpy(line_flags.fstab_line, fstab_line, MAX_FSTAB_LINE_LENGTH);
+ bool found_separator = false;
+ char *fs_loc = NULL;
+ char *block_loc = NULL;
+ char *flags_loc = NULL;
+ size_t index, item_index = 0;
+ for (index = 0; index < line_size; index++) {
+ if (fstab_line[index] <= 32) {
+ fstab_line[index] = '\0';
+ found_separator = true;
+ } else if (found_separator) {
+ if (item_index == 0) {
+ fs_loc = fstab_line + index;
+ } else if (item_index == 1) {
+ block_loc = fstab_line + index;
+ } else if (item_index > 1) {
+ char *ptr = fstab_line + index;
+ if (*ptr == '/') {
+ line_flags.Alternate_Block_Device = ptr;
+ } else if (strlen(ptr) > strlen("flags=") && strncmp(ptr, "flags=", strlen("flags=")) == 0) {
+ flags_loc = ptr;
+ // Once we find the flags=, we're done scanning the line
+ break;
+ }
+ }
+ found_separator = false;
+ item_index++;
+ }
+ }
+ if (block_loc)
+ line_flags.Primary_Block_Device = block_loc;
+ if (fs_loc)
+ line_flags.File_System = fs_loc;
+ if (flags_loc)
+ line_flags.Flags = flags_loc;
+ string Mount_Point = fstab_line;
+ twrp_flags[Mount_Point] = line_flags;
+ memset(fstab_line, 0, sizeof(fstab_line));
+ }
+ fclose(fstabFile);
+ }
fstabFile = fopen(Fstab_Filename.c_str(), "rt");
if (fstabFile == NULL) {
LOGERR("Critical Error: Unable to open fstab at '%s'.\n", Fstab_Filename.c_str());
return false;
- }
+ } else
+ LOGINFO("Reading %s\n", Fstab_Filename.c_str());
while (fgets(fstab_line, sizeof(fstab_line), fstabFile) != NULL) {
if (fstab_line[0] != '/')
continue;
- if (fstab_line[strlen(fstab_line) - 1] != '\n')
- fstab_line[strlen(fstab_line)] = '\n';
+ if (strstr(fstab_line, "swap"))
+ continue; // Skip swap in recovery
+
+ size_t line_size = strlen(fstab_line);
+ if (fstab_line[line_size - 1] != '\n')
+ fstab_line[line_size] = '\n';
TWPartition* partition = new TWPartition();
- if (partition->Process_Fstab_Line(fstab_line, Display_Error))
+ if (partition->Process_Fstab_Line(fstab_line, Display_Error, &twrp_flags))
Partitions.push_back(partition);
else
delete partition;
@@ -122,6 +196,24 @@ int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error)
}
fclose(fstabFile);
+ if (twrp_flags.size() > 0) {
+ LOGINFO("Processing remaining twrp.flags\n");
+ // Add any items from twrp.flags that did not exist in the recovery.fstab
+ for (std::map<string, Flags_Map>::iterator mapit=twrp_flags.begin(); mapit!=twrp_flags.end(); mapit++) {
+ if (Find_Partition_By_Path(mapit->first) == NULL) {
+ TWPartition* partition = new TWPartition();
+ if (partition->Process_Fstab_Line(mapit->second.fstab_line, Display_Error, NULL))
+ Partitions.push_back(partition);
+ else
+ delete partition;
+ }
+ if (mapit->second.fstab_line)
+ free(mapit->second.fstab_line);
+ mapit->second.fstab_line = NULL;
+ }
+ }
+ LOGINFO("Done processing fstab files\n");
+
std::vector<TWPartition*>::iterator iter;
for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
(*iter)->Partition_Post_Processing(Display_Error);
@@ -216,6 +308,7 @@ int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error)
#ifdef AB_OTA_UPDATER
DataManager::SetValue("tw_active_slot", Get_Active_Slot_Display());
#endif
+ setup_uevent();
return true;
}
@@ -326,6 +419,8 @@ void TWPartitionManager::Output_Partition(TWPartition* Part) {
printf("Is_Adopted_Storage ");
if (Part->SlotSelect)
printf("SlotSelect ");
+ if (Part->Mount_Read_Only)
+ printf("Mount_Read_Only ");
printf("\n");
if (!Part->SubPartition_Of.empty())
printf(" SubPartition_Of: %s\n", Part->SubPartition_Of.c_str());
@@ -367,7 +462,7 @@ void TWPartitionManager::Output_Partition(TWPartition* Part) {
printf(" MTD_Name: %s\n", Part->MTD_Name.c_str());
printf(" Backup_Method: %s\n", Part->Backup_Method_By_Name().c_str());
if (Part->Mount_Flags || !Part->Mount_Options.empty())
- printf(" Mount_Options: %s\n", Part->Mount_Options.c_str());
+ printf(" Mount_Flags: %i, Mount_Options: %s\n", Part->Mount_Flags, Part->Mount_Options.c_str());
if (Part->MTP_Storage_ID)
printf(" MTP_Storage_ID: %i\n", Part->MTP_Storage_ID);
printf("\n");
@@ -452,7 +547,7 @@ int TWPartitionManager::Mount_Settings_Storage(bool Display_Error) {
return Mount_By_Path(DataManager::GetSettingsStoragePath(), Display_Error);
}
-TWPartition* TWPartitionManager::Find_Partition_By_Path(string Path) {
+TWPartition* TWPartitionManager::Find_Partition_By_Path(const string& Path) {
std::vector<TWPartition*>::iterator iter;
string Local_Path = TWFunc::Get_Root_Path(Path);
@@ -463,6 +558,16 @@ TWPartition* TWPartitionManager::Find_Partition_By_Path(string Path) {
return NULL;
}
+TWPartition* TWPartitionManager::Find_Partition_By_Block_Device(const string& Block_Device) {
+ std::vector<TWPartition*>::iterator iter;
+
+ for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+ if ((*iter)->Primary_Block_Device == Block_Device || (!(*iter)->Actual_Block_Device.empty() && (*iter)->Actual_Block_Device == Block_Device))
+ return (*iter);
+ }
+ return NULL;
+}
+
int TWPartitionManager::Check_Backup_Name(bool Display_Error) {
// Check the backup name to ensure that it is the correct size and contains only valid characters
// and that a backup with that name doesn't already exist
@@ -1631,7 +1736,7 @@ int TWPartitionManager::Open_Lun_File(string Partition_Path, string Lun_File) {
if (!Part->UnMount(true) || !Part->Is_Present)
return false;
- if (TWFunc::write_file(Lun_File, Part->Actual_Block_Device)) {
+ if (TWFunc::write_to_file(Lun_File, Part->Actual_Block_Device)) {
LOGERR("Unable to write to ums lunfile '%s': (%s)\n", Lun_File.c_str(), strerror(errno));
return false;
}
@@ -1703,7 +1808,7 @@ int TWPartitionManager::usb_storage_disable(void) {
for (index=0; index<2; index++) {
sprintf(lun_file, CUSTOM_LUN_FILE, index);
- ret = TWFunc::write_file(lun_file, str);
+ ret = TWFunc::write_to_file(lun_file, str);
if (ret < 0) {
break;
}
@@ -1914,7 +2019,7 @@ void TWPartitionManager::Get_Partition_List(string ListType, std::vector<Partiti
std::vector<TWPartition*>::iterator iter;
if (ListType == "mount") {
for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
- if ((*iter)->Can_Be_Mounted && !(*iter)->Is_SubPartition) {
+ if ((*iter)->Can_Be_Mounted) {
struct PartitionList part;
part.Display_Name = (*iter)->Display_Name;
part.Mount_Point = (*iter)->Mount_Point;
@@ -2108,8 +2213,8 @@ bool TWPartitionManager::Enable_MTP(void) {
property_get("usb.product.mtpadb", product, "4EE2");
string vendorstr = vendor;
string productstr = product;
- TWFunc::write_file("/sys/class/android_usb/android0/idVendor", vendorstr);
- TWFunc::write_file("/sys/class/android_usb/android0/idProduct", productstr);
+ TWFunc::write_to_file("/sys/class/android_usb/android0/idVendor", vendorstr);
+ TWFunc::write_to_file("/sys/class/android_usb/android0/idProduct", productstr);
property_set("sys.usb.config", "mtp,adb");
}
/* To enable MTP debug, use the twrp command line feature:
@@ -2163,8 +2268,8 @@ bool TWPartitionManager::Disable_MTP(void) {
property_get("usb.product.adb", product, "D001");
string vendorstr = vendor;
string productstr = product;
- TWFunc::write_file("/sys/class/android_usb/android0/idVendor", vendorstr);
- TWFunc::write_file("/sys/class/android_usb/android0/idProduct", productstr);
+ TWFunc::write_to_file("/sys/class/android_usb/android0/idVendor", vendorstr);
+ TWFunc::write_to_file("/sys/class/android_usb/android0/idProduct", productstr);
usleep(2000);
}
#ifdef TW_HAS_MTP
@@ -2226,15 +2331,23 @@ bool TWPartitionManager::Add_Remove_MTP_Storage(TWPartition* Part, int message_t
} else if (message_type == MTP_MESSAGE_ADD_STORAGE && Part->Is_Mounted()) {
mtp_message.message_type = MTP_MESSAGE_ADD_STORAGE; // Add
mtp_message.storage_id = Part->MTP_Storage_ID;
- mtp_message.path = Part->Storage_Path.c_str();
- mtp_message.display = Part->Storage_Name.c_str();
+ if (Part->Storage_Path.size() >= sizeof(mtp_message.path)) {
+ LOGERR("Storage path '%s' too large for mtpmsg\n", Part->Storage_Path.c_str());
+ return false;
+ }
+ strcpy(mtp_message.path, Part->Storage_Path.c_str());
+ if (Part->Storage_Name.size() >= sizeof(mtp_message.display)) {
+ LOGERR("Storage name '%s' too large for mtpmsg\n", Part->Storage_Name.c_str());
+ return false;
+ }
+ strcpy(mtp_message.display, Part->Storage_Name.c_str());
mtp_message.maxFileSize = Part->Get_Max_FileSize();
LOGINFO("sending message to add %i '%s' '%s'\n", mtp_message.storage_id, mtp_message.path, mtp_message.display);
if (write(mtp_write_fd, &mtp_message, sizeof(mtp_message)) <= 0) {
LOGINFO("error sending message to add storage %i\n", Part->MTP_Storage_ID);
return false;
} else {
- LOGINFO("Message sent, add storage ID: %i\n", Part->MTP_Storage_ID);
+ LOGINFO("Message sent, add storage ID: %i '%s'\n", Part->MTP_Storage_ID, mtp_message.path);
return true;
}
} else {
@@ -2444,15 +2557,23 @@ void TWPartitionManager::Translate_Partition_Display_Names() {
if (part)
part->Backup_Display_Name = gui_lookup("android_secure", "Android Secure");
+ std::vector<TWPartition*>::iterator sysfs;
+ for (sysfs = Partitions.begin(); sysfs != Partitions.end(); sysfs++) {
+ if (!(*sysfs)->Sysfs_Entry.empty()) {
+ Translate_Partition((*sysfs)->Mount_Point.c_str(), "autostorage", "Storage", "autostorage", "Storage");
+ }
+ }
+
// This updates the text on all of the storage selection buttons in the GUI
DataManager::SetBackupFolder();
}
-void TWPartitionManager::Decrypt_Adopted() {
+bool TWPartitionManager::Decrypt_Adopted() {
#ifdef TW_INCLUDE_CRYPTO
+ bool ret = false;
if (!Mount_By_Path("/data", false)) {
LOGERR("Cannot decrypt adopted storage because /data will not mount\n");
- return;
+ return false;
}
LOGINFO("Decrypt adopted storage starting\n");
char* xmlFile = PageManager::LoadFileToBuffer("/data/system/storage.xml", NULL);
@@ -2470,11 +2591,15 @@ void TWPartitionManager::Decrypt_Adopted() {
Primary_Storage_UUID = psuuid->value();
}
}
+ } else {
+ LOGINFO("No /data/system/storage.xml for adopted storage\n");
+ return false;
}
std::vector<TWPartition*>::iterator adopt;
for (adopt = Partitions.begin(); adopt != Partitions.end(); adopt++) {
if ((*adopt)->Removable && (*adopt)->Is_Present) {
if ((*adopt)->Decrypt_Adopted() == 0) {
+ ret = true;
if (volumes) {
xml_node<>* volume = volumes->first_node("volume");
while (volume) {
@@ -2525,9 +2650,10 @@ void TWPartitionManager::Decrypt_Adopted() {
delete doc;
free(xmlFile);
}
+ return ret;
#else
LOGINFO("Decrypt_Adopted: no crypto support\n");
- return;
+ return false;
#endif
}
@@ -2586,3 +2712,202 @@ string TWPartitionManager::Get_Active_Slot_Suffix() {
string TWPartitionManager::Get_Active_Slot_Display() {
return Active_Slot_Display;
}
+
+void TWPartitionManager::Remove_Uevent_Devices(const string& Mount_Point) {
+ std::vector<TWPartition*>::iterator iter;
+
+ for (iter = Partitions.begin(); iter != Partitions.end(); ) {
+ if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Mount_Point) {
+ TWPartition *part = *iter;
+ LOGINFO("%s was removed by uevent data\n", (*iter)->Mount_Point.c_str());
+ (*iter)->UnMount(false);
+ rmdir((*iter)->Mount_Point.c_str());
+ iter = Partitions.erase(iter);
+ delete part;
+ } else {
+ iter++;
+ }
+ }
+}
+
+void TWPartitionManager::Handle_Uevent(const Uevent_Block_Data& uevent_data) {
+ std::vector<TWPartition*>::iterator iter;
+
+ for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+ if (!(*iter)->Sysfs_Entry.empty()) {
+ string device;
+ size_t wildcard = (*iter)->Sysfs_Entry.find("*");
+ if (wildcard != string::npos) {
+ device = (*iter)->Sysfs_Entry.substr(0, wildcard);
+ } else {
+ device = (*iter)->Sysfs_Entry;
+ }
+ if (device == uevent_data.sysfs_path.substr(0, device.size())) {
+ // Found a match
+ if (uevent_data.action == "add") {
+ (*iter)->Primary_Block_Device = "/dev/block/" + uevent_data.block_device;
+ (*iter)->Alternate_Block_Device = (*iter)->Primary_Block_Device;
+ (*iter)->Is_Present = true;
+ LOGINFO("Found a match '%s' '%s'\n", uevent_data.block_device.c_str(), device.c_str());
+ if (!Decrypt_Adopted()) {
+ LOGINFO("No adopted storage so finding actual block device\n");
+ (*iter)->Find_Actual_Block_Device();
+ }
+ return;
+ } else if (uevent_data.action == "remove") {
+ (*iter)->Is_Present = false;
+ (*iter)->Primary_Block_Device = "";
+ (*iter)->Actual_Block_Device = "";
+ Remove_Uevent_Devices((*iter)->Mount_Point);
+ return;
+ }
+ }
+ }
+ }
+ LOGINFO("Found no matching fstab entry for uevent device '%s' - %s\n", uevent_data.sysfs_path.c_str(), uevent_data.action.c_str());
+}
+
+void TWPartitionManager::setup_uevent() {
+ struct sockaddr_nl nls;
+
+ if (uevent_pfd.fd >= 0) {
+ LOGINFO("uevent already set up\n");
+ return;
+ }
+
+ // Open hotplug event netlink socket
+ memset(&nls,0,sizeof(struct sockaddr_nl));
+ nls.nl_family = AF_NETLINK;
+ nls.nl_pid = getpid();
+ nls.nl_groups = -1;
+ uevent_pfd.events = POLLIN;
+ uevent_pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+ if (uevent_pfd.fd==-1) {
+ LOGERR("uevent not root\n");
+ return;
+ }
+
+ // Listen to netlink socket
+ if (::bind(uevent_pfd.fd, (struct sockaddr *) &nls, sizeof(struct sockaddr_nl)) < 0) {
+ LOGERR("Bind failed\n");
+ return;
+ }
+ set_select_fd();
+ Coldboot();
+}
+
+Uevent_Block_Data TWPartitionManager::get_event_block_values(char *buf, int len) {
+ Uevent_Block_Data ret;
+ ret.subsystem = "";
+ char *ptr = buf;
+ const char *end = buf + len;
+
+ buf[len - 1] = '\0';
+ while (ptr < end) {
+ if (strncmp(ptr, "ACTION=", strlen("ACTION=")) == 0) {
+ ptr += strlen("ACTION=");
+ ret.action = ptr;
+ } else if (strncmp(ptr, "SUBSYSTEM=", strlen("SUBSYSTEM=")) == 0) {
+ ptr += strlen("SUBSYSTEM=");
+ ret.subsystem = ptr;
+ } else if (strncmp(ptr, "DEVTYPE=", strlen("DEVTYPE=")) == 0) {
+ ptr += strlen("DEVTYPE=");
+ ret.type = ptr;
+ } else if (strncmp(ptr, "DEVPATH=", strlen("DEVPATH=")) == 0) {
+ ptr += strlen("DEVPATH=");
+ ret.sysfs_path += ptr;
+ } else if (strncmp(ptr, "DEVNAME=", strlen("DEVNAME=")) == 0) {
+ ptr += strlen("DEVNAME=");
+ ret.block_device += ptr;
+ } else if (strncmp(ptr, "MAJOR=", strlen("MAJOR=")) == 0) {
+ ptr += strlen("MAJOR=");
+ ret.major = atoi(ptr);
+ } else if (strncmp(ptr, "MINOR=", strlen("MINOR=")) == 0) {
+ ptr += strlen("MINOR=");
+ ret.minor = atoi(ptr);
+ }
+ ptr += strlen(ptr) + 1;
+ }
+ return ret;
+}
+
+void TWPartitionManager::read_uevent() {
+ char buf[1024];
+
+ int len = recv(uevent_pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
+ if (len == -1) {
+ LOGERR("recv error on uevent\n");
+ return;
+ }
+ /*int i = 0; // Print all uevent output for test /debug
+ while (i<len) {
+ printf("%s\n", buf+i);
+ i += strlen(buf+i)+1;
+ }*/
+ Uevent_Block_Data uevent_data = get_event_block_values(buf, len);
+ if (uevent_data.subsystem == "block" && uevent_data.type == "disk") {
+ PartitionManager.Handle_Uevent(uevent_data);
+ }
+}
+
+void TWPartitionManager::close_uevent() {
+ if (uevent_pfd.fd > 0)
+ close(uevent_pfd.fd);
+ uevent_pfd.fd = -1;
+}
+
+void TWPartitionManager::Add_Partition(TWPartition* Part) {
+ Partitions.push_back(Part);
+}
+
+void TWPartitionManager::Coldboot_Scan(std::vector<string> *sysfs_entries, const string& Path, int depth) {
+ string Real_Path = Path;
+ char real_path[PATH_MAX];
+ if (realpath(Path.c_str(), &real_path[0])) {
+ string Real_Path = real_path;
+ std::vector<string>::iterator iter;
+ for (iter = sysfs_entries->begin(); iter != sysfs_entries->end(); iter++) {
+ if (Real_Path.find((*iter)) != string::npos) {
+ string Write_Path = Real_Path + "/uevent";
+ if (TWFunc::Path_Exists(Write_Path)) {
+ const char* write_val = "add\n";
+ TWFunc::write_to_file(Write_Path, write_val);
+ break;
+ }
+ }
+ }
+ }
+
+ DIR* d = opendir(Path.c_str());
+ if (d != NULL) {
+ struct dirent* de;
+ while ((de = readdir(d)) != NULL) {
+ if (de->d_name[0] == '.' || (de->d_type != DT_DIR && depth > 0))
+ continue;
+ if (strlen(de->d_name) >= 4 && (strncmp(de->d_name, "ram", 3) == 0 || strncmp(de->d_name, "loop", 4) == 0))
+ continue;
+
+ string item = Path + "/";
+ item.append(de->d_name);
+ Coldboot_Scan(sysfs_entries, item, depth + 1);
+ }
+ closedir(d);
+ }
+}
+
+void TWPartitionManager::Coldboot() {
+ std::vector<TWPartition*>::iterator iter;
+ std::vector<string> sysfs_entries;
+
+ for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+ if (!(*iter)->Sysfs_Entry.empty()) {
+ size_t wildcard_pos = (*iter)->Sysfs_Entry.find("*");
+ if (wildcard_pos == string::npos)
+ wildcard_pos = (*iter)->Sysfs_Entry.size();
+ sysfs_entries.push_back((*iter)->Sysfs_Entry.substr(0, wildcard_pos));
+ }
+ }
+
+ if (sysfs_entries.size() > 0)
+ Coldboot_Scan(&sysfs_entries, "/sys/block", 0);
+}