diff options
Diffstat (limited to '')
-rw-r--r-- | partition.cpp | 351 |
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; |