summaryrefslogtreecommitdiffstats
path: root/partition.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'partition.cpp')
-rw-r--r--partition.cpp351
1 files changed, 296 insertions, 55 deletions
diff --git a/partition.cpp b/partition.cpp
index 4157e9791..8b73f646b 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -77,40 +77,47 @@ extern "C" {
using namespace std;
+static int auto_index = 0; // v2 fstab allows you to specify a mount point of "auto" with no /. These items are given a mount point of /auto* where * == auto_index
+
extern struct selabel_handle *selinux_handle;
extern bool datamedia;
struct flag_list {
const char *name;
- unsigned flag;
+ unsigned long flag;
};
const struct flag_list mount_flags[] = {
- { "noatime", MS_NOATIME },
- { "noexec", MS_NOEXEC },
- { "nosuid", MS_NOSUID },
- { "nodev", MS_NODEV },
- { "nodiratime", MS_NODIRATIME },
- { "ro", MS_RDONLY },
- { "rw", 0 },
- { "remount", MS_REMOUNT },
- { "bind", MS_BIND },
- { "rec", MS_REC },
+ { "noatime", MS_NOATIME },
+ { "noexec", MS_NOEXEC },
+ { "nosuid", MS_NOSUID },
+ { "nodev", MS_NODEV },
+ { "nodiratime", MS_NODIRATIME },
+ { "ro", MS_RDONLY },
+ { "rw", 0 },
+ { "remount", MS_REMOUNT },
+ { "bind", MS_BIND },
+ { "rec", MS_REC },
#ifdef MS_UNBINDABLE
- { "unbindable", MS_UNBINDABLE },
+ { "unbindable", MS_UNBINDABLE },
#endif
#ifdef MS_PRIVATE
- { "private", MS_PRIVATE },
+ { "private", MS_PRIVATE },
#endif
#ifdef MS_SLAVE
- { "slave", MS_SLAVE },
+ { "slave", MS_SLAVE },
#endif
#ifdef MS_SHARED
- { "shared", MS_SHARED },
+ { "shared", MS_SHARED },
#endif
- { "sync", MS_SYNCHRONOUS },
- { "defaults", 0 },
- { 0, 0 },
+ { "sync", MS_SYNCHRONOUS },
+ { 0, 0 },
+};
+
+const char *ignored_mount_items[] = {
+ "defaults=",
+ "errors=",
+ NULL
};
enum TW_FSTAB_FLAGS {
@@ -141,6 +148,14 @@ enum TW_FSTAB_FLAGS {
TWFLAG_WIPEDURINGFACTORYRESET,
TWFLAG_WIPEINGUI,
TWFLAG_SLOTSELECT,
+ TWFLAG_WAIT,
+ TWFLAG_VERIFY,
+ TWFLAG_CHECK,
+ TWFLAG_ALTDEVICE,
+ TWFLAG_NOTRIM,
+ TWFLAG_VOLDMANAGED,
+ TWFLAG_FORMATTABLE,
+ TWFLAG_RESIZE,
};
/* Flags without a trailing '=' are considered dual format flags and can be
@@ -175,6 +190,14 @@ const struct flag_list tw_flags[] = {
{ "wipeduringfactoryreset", TWFLAG_WIPEDURINGFACTORYRESET },
{ "wipeingui", TWFLAG_WIPEINGUI },
{ "slotselect", TWFLAG_SLOTSELECT },
+ { "wait", TWFLAG_WAIT },
+ { "verify", TWFLAG_VERIFY },
+ { "check", TWFLAG_CHECK },
+ { "altdevice", TWFLAG_ALTDEVICE },
+ { "notrim", TWFLAG_NOTRIM },
+ { "voldmanaged=", TWFLAG_VOLDMANAGED },
+ { "formattable", TWFLAG_FORMATTABLE },
+ { "resize", TWFLAG_RESIZE },
{ 0, 0 },
};
@@ -192,6 +215,8 @@ TWPartition::TWPartition() {
Symlink_Mount_Point = "";
Mount_Point = "";
Backup_Path = "";
+ Wildcard_Block_Device = false;
+ Sysfs_Entry = "";
Actual_Block_Device = "";
Primary_Block_Device = "";
Alternate_Block_Device = "";
@@ -242,12 +267,15 @@ TWPartition::~TWPartition(void) {
// Do nothing
}
-bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error) {
+bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error, std::map<string, Flags_Map> *twrp_flags) {
char full_line[MAX_FSTAB_LINE_LENGTH];
char twflags[MAX_FSTAB_LINE_LENGTH] = "";
char* ptr;
int line_len = strlen(fstab_line), index = 0, item_index = 0;
bool skip = false;
+ int fstab_version = 1, mount_point_index = 0, fs_index = 1, block_device_index = 2;
+ TWPartition *additional_entry = NULL;
+ std::map<string, Flags_Map>::iterator it;
strlcpy(full_line, fstab_line, sizeof(full_line));
for (index = 0; index < line_len; index++) {
@@ -256,26 +284,43 @@ bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error)
if (!skip && full_line[index] <= 32)
full_line[index] = '\0';
}
- Mount_Point = full_line;
- LOGINFO("Processing '%s'\n", Mount_Point.c_str());
- Backup_Path = Mount_Point;
- Storage_Path = Mount_Point;
- Display_Name = full_line + 1;
- Backup_Display_Name = Display_Name;
- Storage_Name = Display_Name;
- index = Mount_Point.size();
+ if (line_len < 10)
+ return false; // There can't possibly be a valid fstab line that is less than 10 chars
+ if (strncmp(fstab_line, "/dev/", strlen("/dev/")) == 0 || strncmp(fstab_line, "/devices/", strlen("/devices/")) == 0) {
+ fstab_version = 2;
+ block_device_index = 0;
+ mount_point_index = 1;
+ fs_index = 2;
+ }
+
+ index = 0;
while (index < line_len) {
while (index < line_len && full_line[index] == '\0')
index++;
if (index >= line_len)
continue;
ptr = full_line + index;
- if (item_index == 0) {
+ if (item_index == mount_point_index) {
+ Mount_Point = ptr;
+ if (fstab_version == 2) {
+ additional_entry = PartitionManager.Find_Partition_By_Path(Mount_Point);
+ if (additional_entry) {
+ LOGINFO("Found an additional entry for '%s'\n", Mount_Point.c_str());
+ }
+ }
+ LOGINFO("Processing '%s'\n", Mount_Point.c_str());
+ Backup_Path = Mount_Point;
+ Storage_Path = Mount_Point;
+ Display_Name = ptr + 1;
+ Backup_Display_Name = Display_Name;
+ Storage_Name = Display_Name;
+ item_index++;
+ } else if (item_index == fs_index) {
// File System
Fstab_File_System = ptr;
Current_File_System = ptr;
item_index++;
- } else if (item_index == 1) {
+ } else if (item_index == block_device_index) {
// Primary Block Device
if (Fstab_File_System == "mtd" || Fstab_File_System == "yaffs2") {
MTD_Name = ptr;
@@ -299,8 +344,19 @@ bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error)
Find_Real_Block_Device(Primary_Block_Device, Display_Error);
}
item_index++;
- } else if (item_index > 1) {
- if (*ptr == '/') {
+ } else if (item_index > 2) {
+ if (fstab_version == 2) {
+ if (item_index == 3) {
+ Process_FS_Flags(ptr);
+ if (additional_entry) {
+ additional_entry->Save_FS_Flags(Fstab_File_System, Mount_Flags, Mount_Options);
+ return false; // We save the extra fs flags in the other partition entry and by returning false, this entry will be deleted
+ }
+ } else {
+ strlcpy(twflags, ptr, sizeof(twflags));
+ }
+ item_index++;
+ } else if (*ptr == '/') { // v2 fstab does not allow alternate block devices
// Alternate Block Device
Alternate_Block_Device = ptr;
Find_Real_Block_Device(Alternate_Block_Device, Display_Error);
@@ -323,7 +379,50 @@ bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error)
index++;
}
- if (!Is_File_System(Fstab_File_System) && !Is_Image(Fstab_File_System)) {
+ // override block devices from the v2 fstab with the ones we read from the twrp.flags file in case they are different
+ if (fstab_version == 2 && twrp_flags && twrp_flags->size() > 0) {
+ it = twrp_flags->find(Mount_Point);
+ if (it != twrp_flags->end()) {
+ if (!it->second.Primary_Block_Device.empty()) {
+ Primary_Block_Device = it->second.Primary_Block_Device;
+ Find_Real_Block_Device(Primary_Block_Device, Display_Error);
+ }
+ if (!it->second.Alternate_Block_Device.empty()) {
+ Alternate_Block_Device = it->second.Alternate_Block_Device;
+ Find_Real_Block_Device(Alternate_Block_Device, Display_Error);
+ }
+ }
+ }
+
+ if (strncmp(fstab_line, "/devices/", strlen("/devices/")) == 0) {
+ Sysfs_Entry = Primary_Block_Device;
+ Primary_Block_Device = "";
+ Is_Storage = true;
+ Removable = true;
+ Wipe_Available_in_GUI = true;
+ Wildcard_Block_Device = true;
+ }
+ if (Primary_Block_Device.find("*") != string::npos)
+ Wildcard_Block_Device = true;
+
+ if (Mount_Point == "auto") {
+ Mount_Point = "/auto";
+ char autoi[5];
+ sprintf(autoi, "%i", auto_index);
+ Mount_Point += autoi;
+ Backup_Path = Mount_Point;
+ Storage_Path = Mount_Point;
+ auto_index++;
+ Setup_File_System(Display_Error);
+ Display_Name = "Storage";
+ Backup_Display_Name = Display_Name;
+ Storage_Name = Display_Name;
+ Can_Be_Backed_Up = false;
+ Wipe_Available_in_GUI = true;
+ Is_Storage = true;
+ Removable = true;
+ Wipe_Available_in_GUI = true;
+ } else if (!Is_File_System(Fstab_File_System) && !Is_Image(Fstab_File_System)) {
if (Display_Error)
LOGERR("Unknown File System: '%s'\n", Fstab_File_System.c_str());
else
@@ -448,7 +547,8 @@ bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error)
Storage_Name = "";
Backup_Display_Name = "";
- Process_TW_Flags(twflags, Display_Error);
+ Process_TW_Flags(twflags, (fstab_version == 1), fstab_version);
+ Save_FS_Flags(Fstab_File_System, Mount_Flags, Mount_Options);
bool has_display_name = !Display_Name.empty();
bool has_storage_name = !Storage_Name.empty();
@@ -466,6 +566,21 @@ bool TWPartition::Process_Fstab_Line(const char *fstab_line, bool Display_Error)
if (!has_display_name && has_backup_name)
Display_Name = Backup_Display_Name;
}
+
+ if (fstab_version == 2 && twrp_flags && twrp_flags->size() > 0) {
+ it = twrp_flags->find(Mount_Point);
+ if (it != twrp_flags->end()) {
+ char twrpflags[MAX_FSTAB_LINE_LENGTH] = "";
+ int skip = 0;
+ string Flags = it->second.Flags;
+ strcpy(twrpflags, Flags.c_str());
+ if (strlen(twrpflags) > strlen("flags=") && strncmp(twrpflags, "flags=", strlen("flags=")) == 0)
+ skip += strlen("flags=");
+ char* flagptr = twrpflags;
+ flagptr += skip;
+ Process_TW_Flags(flagptr, Display_Error, 1); // Forcing the fstab to ver 1 because this data is coming from the /etc/twrp.flags which should be using the TWRP v1 flags format
+ }
+ }
return true;
}
@@ -599,35 +714,59 @@ void TWPartition::Process_FS_Flags(const char *str) {
Mount_Options = "";
// Avoid issues with potentially nested strtok by using strtok_r
- ptr = strtok_r(options, ",", &savep);
- while (ptr) {
- const struct flag_list* mount_flag = mount_flags;
+ for (ptr = strtok_r(options, ",", &savep); ptr; ptr = strtok_r(NULL, ",", &savep)) {
+ char *equals = strstr(ptr, "=");
+ size_t name_len;
- for (; mount_flag->name; mount_flag++) {
- // mount_flags are never postfixed by '=',
- // so only match identical strings (including length)
- if (strcmp(ptr, mount_flag->name) == 0) {
- Mount_Flags |= mount_flag->flag;
+ if (!equals)
+ name_len = strlen(ptr);
+ else
+ name_len = equals - ptr;
+
+ // There are some flags that we want to ignore in TWRP
+ bool found_match = false;
+ for (const char** ignored_mount_item = ignored_mount_items; *ignored_mount_item; ignored_mount_item++) {
+ if (strncmp(ptr, *ignored_mount_item, name_len) == 0) {
+ found_match = true;
break;
}
}
+ if (found_match)
+ continue;
- if (mount_flag->flag == MS_RDONLY)
- Mount_Read_Only = true;
-
- if (mount_flag->name != 0) {
- if (!Mount_Options.empty())
- Mount_Options += ",";
- Mount_Options += mount_flag->name;
- } else {
- LOGINFO("Unhandled mount flag: '%s'\n", ptr);
+ // mount_flags are never postfixed by '='
+ if (!equals) {
+ const struct flag_list* mount_flag = mount_flags;
+ for (; mount_flag->name; mount_flag++) {
+ if (strcmp(ptr, mount_flag->name) == 0) {
+ if (mount_flag->flag == MS_RDONLY)
+ Mount_Read_Only = true;
+ else
+ Mount_Flags |= (unsigned)mount_flag->flag;
+ found_match = true;
+ break;
+ }
+ }
+ if (found_match)
+ continue;
}
- ptr = strtok_r(NULL, ",", &savep);
+ // If we aren't ignoring this flag and it's not a mount flag, then it must be a mount option
+ if (!Mount_Options.empty())
+ Mount_Options += ",";
+ Mount_Options += ptr;
}
free(options);
}
+void TWPartition::Save_FS_Flags(const string& local_File_System, int local_Mount_Flags, const string& local_Mount_Options) {
+ partition_fs_flags_struct flags;
+ flags.File_System = local_File_System;
+ flags.Mount_Flags = local_Mount_Flags;
+ flags.Mount_Options = local_Mount_Options;
+ fs_flags.push_back(flags);
+}
+
void TWPartition::Apply_TW_Flag(const unsigned flag, const char* str, const bool val) {
switch (flag) {
case TWFLAG_ANDSEC:
@@ -649,6 +788,12 @@ void TWPartition::Apply_TW_Flag(const unsigned flag, const char* str, const bool
Can_Encrypt_Backup = val;
break;
case TWFLAG_DEFAULTS:
+ case TWFLAG_WAIT:
+ case TWFLAG_VERIFY:
+ case TWFLAG_CHECK:
+ case TWFLAG_NOTRIM:
+ case TWFLAG_VOLDMANAGED:
+ case TWFLAG_RESIZE:
// Do nothing
break;
case TWFLAG_DISPLAY:
@@ -713,6 +858,7 @@ void TWPartition::Apply_TW_Flag(const unsigned flag, const char* str, const bool
}
break;
case TWFLAG_WIPEINGUI:
+ case TWFLAG_FORMATTABLE:
Wipe_Available_in_GUI = val;
if (Wipe_Available_in_GUI)
Can_Be_Wiped = true;
@@ -720,6 +866,9 @@ void TWPartition::Apply_TW_Flag(const unsigned flag, const char* str, const bool
case TWFLAG_SLOTSELECT:
SlotSelect = true;
break;
+ case TWFLAG_ALTDEVICE:
+ Alternate_Block_Device = str;
+ break;
default:
// Should not get here
LOGINFO("Flag identified for processing, but later unmatched: %i\n", flag);
@@ -727,16 +876,20 @@ void TWPartition::Apply_TW_Flag(const unsigned flag, const char* str, const bool
}
}
-void TWPartition::Process_TW_Flags(char *flags, bool Display_Error) {
+void TWPartition::Process_TW_Flags(char *flags, bool Display_Error, int fstab_ver) {
char separator[2] = {'\n', 0};
char *ptr, *savep;
+ char source_separator = ';';
+
+ if (fstab_ver == 2)
+ source_separator = ',';
// Semicolons within double-quotes are not forbidden, so replace
// only the semicolons intended as separators with '\n' for strtok
for (unsigned i = 0, skip = 0; i < strlen(flags); i++) {
if (flags[i] == '\"')
skip = !skip;
- if (!skip && flags[i] == ';')
+ if (!skip && flags[i] == source_separator)
flags[i] = separator[0];
}
@@ -925,7 +1078,7 @@ void TWPartition::Setup_Data_Media() {
}
void TWPartition::Find_Real_Block_Device(string& Block, bool Display_Error) {
- char device[512], realDevice[512];
+ char device[PATH_MAX], realDevice[PATH_MAX];
strcpy(device, Block.c_str());
memset(realDevice, 0, sizeof(realDevice));
@@ -1826,6 +1979,23 @@ void TWPartition::Check_FS_Type() {
Current_File_System = type;
blkid_free_probe(pr);
+ if (fs_flags.size() > 1) {
+ std::vector<partition_fs_flags_struct>::iterator iter;
+ std::vector<partition_fs_flags_struct>::iterator found = fs_flags.begin();
+
+ for (iter = fs_flags.begin(); iter != fs_flags.end(); iter++) {
+ if (iter->File_System == Current_File_System) {
+ found = iter;
+ break;
+ }
+ }
+ // If we don't find a match, we default the flags to the first set of flags that we received from the fstab
+ if (Mount_Flags != found->Mount_Flags || Mount_Options != found->Mount_Options) {
+ Mount_Flags = found->Mount_Flags;
+ Mount_Options = found->Mount_Options;
+ LOGINFO("Mount_Flags: %i, Mount_Options: %s\n", Mount_Flags, Mount_Options.c_str());
+ }
+ }
}
bool TWPartition::Wipe_EXT23(string File_System) {
@@ -2526,8 +2696,79 @@ bool TWPartition::Update_Size(bool Display_Error) {
return true;
}
+bool TWPartition::Find_Wildcard_Block_Devices(const string& Device) {
+ int mount_point_index = 0; // we will need to create separate mount points for each partition found and we use this index to name each one
+ string Path = TWFunc::Get_Path(Device);
+ string Dev = TWFunc::Get_Filename(Device);
+ size_t wildcard_index = Dev.find("*");
+ if (wildcard_index != string::npos)
+ Dev = Dev.substr(0, wildcard_index);
+ wildcard_index = Dev.size();
+ DIR* d = opendir(Path.c_str());
+ if (d == NULL) {
+ LOGINFO("Error opening '%s': %s\n", Path.c_str(), strerror(errno));
+ return false;
+ }
+ struct dirent* de;
+ while ((de = readdir(d)) != NULL) {
+ if (de->d_type != DT_BLK || strlen(de->d_name) <= wildcard_index || strncmp(de->d_name, Dev.c_str(), wildcard_index) != 0)
+ continue;
+
+ string item = Path + "/";
+ item.append(de->d_name);
+ if (PartitionManager.Find_Partition_By_Block_Device(item))
+ continue;
+ TWPartition *part = new TWPartition;
+ char buffer[MAX_FSTAB_LINE_LENGTH];
+ sprintf(buffer, "%s %s-%i auto defaults defaults", item.c_str(), Mount_Point.c_str(), ++mount_point_index);
+ part->Process_Fstab_Line(buffer, false, NULL);
+ char display[MAX_FSTAB_LINE_LENGTH];
+ sprintf(display, "%s %i", Storage_Name.c_str(), mount_point_index);
+ part->Storage_Name = display;
+ part->Display_Name = display;
+ part->Primary_Block_Device = item;
+ part->Wildcard_Block_Device = false;
+ part->Is_SubPartition = true;
+ part->SubPartition_Of = Mount_Point;
+ part->Is_Storage = Is_Storage;
+ part->Can_Be_Mounted = true;
+ part->Removable = true;
+ part->Can_Be_Wiped = Can_Be_Wiped;
+ part->Wipe_Available_in_GUI = Wipe_Available_in_GUI;
+ part->Find_Actual_Block_Device();
+ part->Update_Size(false);
+ Has_SubPartition = true;
+ PartitionManager.Output_Partition(part);
+ PartitionManager.Add_Partition(part);
+ }
+ closedir(d);
+ return (mount_point_index > 0);
+}
+
void TWPartition::Find_Actual_Block_Device(void) {
- if (Is_Decrypted && !Decrypted_Block_Device.empty()) {
+ if (!Sysfs_Entry.empty() && Primary_Block_Device.empty() && Decrypted_Block_Device.empty()) {
+ /* Sysfs_Entry.empty() indicates if this is a sysfs entry that begins with /device/
+ * If we have a syfs entry then we are looking for this device from a uevent add.
+ * The uevent add will set the primary block device based on the data we receive from
+ * after checking for adopted storage. If the device ends up being adopted, then the
+ * decrypted block device will be set instead of the primary block device. */
+ Is_Present = false;
+ return;
+ }
+ if (Wildcard_Block_Device && !Is_Adopted_Storage) {
+ Is_Present = false;
+ Actual_Block_Device = "";
+ Can_Be_Mounted = false;
+ if (!Find_Wildcard_Block_Devices(Primary_Block_Device)) {
+ string Dev = Primary_Block_Device.substr(0, Primary_Block_Device.find("*"));
+ if (TWFunc::Path_Exists(Dev)) {
+ Is_Present = true;
+ Can_Be_Mounted = true;
+ Actual_Block_Device = Dev;
+ }
+ }
+ return;
+ } else if (Is_Decrypted && !Decrypted_Block_Device.empty()) {
Actual_Block_Device = Decrypted_Block_Device;
if (TWFunc::Path_Exists(Decrypted_Block_Device)) {
Is_Present = true;