Commit dc864ec8 authored by Dees Troy's avatar Dees Troy Committed by Gerrit Code Review
Browse files

Merge "Support v2 fstab format" into android-8.0

parents dcd9f3f3 6e8c27a5
/*update
/*
Copyright 2013 bigbiff/Dees_Troy TeamWin
This file is part of TWRP/TeamWin Recovery Project.
......
......@@ -33,7 +33,6 @@
#include <sys/mount.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
extern "C"
{
......@@ -79,6 +78,8 @@ int gGuiRunning = 0;
int g_pty_fd = -1; // set by terminal on init
void terminal_pty_read();
int select_fd = 0;
static int gRecorder = -1;
extern "C" void gr_write_frame_to_file(int fd);
......@@ -395,9 +396,18 @@ void InputHandler::handleDrag()
}
}
void set_select_fd() {
select_fd = ors_read_fd + 1;
if (g_pty_fd >= select_fd)
select_fd = g_pty_fd + 1;
if (PartitionManager.uevent_pfd.fd >= select_fd)
select_fd = PartitionManager.uevent_pfd.fd + 1;
}
static void setup_ors_command()
{
ors_read_fd = -1;
set_select_fd();
unlink(ORS_INPUT_FILE);
if (mkfifo(ORS_INPUT_FILE, 06660) != 0) {
......@@ -417,6 +427,7 @@ static void setup_ors_command()
unlink(ORS_INPUT_FILE);
unlink(ORS_OUTPUT_FILE);
}
set_select_fd();
}
// callback called after a CLI command was executed
......@@ -448,6 +459,7 @@ static void ors_command_read()
if (!orsout) {
close(ors_read_fd);
ors_read_fd = -1;
set_select_fd();
LOGINFO("Unable to fopen %s\n", ORS_OUTPUT_FILE);
unlink(ORS_INPUT_FILE);
unlink(ORS_OUTPUT_FILE);
......@@ -554,29 +566,30 @@ static int runPages(const char *page_name, const int stop_on_page_done)
for (;;)
{
loopTimer(input_timeout_ms);
FD_ZERO(&fdset);
timeout.tv_sec = 0;
timeout.tv_usec = 1;
if (g_pty_fd > 0) {
// TODO: this is not nice, we should have one central select for input, pty, and ors
FD_ZERO(&fdset);
FD_SET(g_pty_fd, &fdset);
timeout.tv_sec = 0;
timeout.tv_usec = 1;
has_data = select(g_pty_fd+1, &fdset, NULL, NULL, &timeout);
if (has_data > 0) {
terminal_pty_read();
}
}
if (PartitionManager.uevent_pfd.fd > 0) {
FD_SET(PartitionManager.uevent_pfd.fd, &fdset);
}
#ifndef TW_OEM_BUILD
if (ors_read_fd > 0 && !orsout) { // orsout is non-NULL if a command is still running
FD_ZERO(&fdset);
FD_SET(ors_read_fd, &fdset);
timeout.tv_sec = 0;
timeout.tv_usec = 1;
has_data = select(ors_read_fd+1, &fdset, NULL, NULL, &timeout);
if (has_data > 0) {
ors_command_read();
}
}
#endif
// TODO: combine this select with the poll done by input handling
has_data = select(select_fd, &fdset, NULL, NULL, &timeout);
if (has_data > 0) {
if (g_pty_fd > 0 && FD_ISSET(g_pty_fd, &fdset))
terminal_pty_read();
if (PartitionManager.uevent_pfd.fd > 0 && FD_ISSET(PartitionManager.uevent_pfd.fd, &fdset))
PartitionManager.read_uevent();
if (ors_read_fd > 0 && !orsout && FD_ISSET(ors_read_fd, &fdset))
ors_command_read();
}
if (!gForceRender.get_value())
{
......@@ -636,6 +649,7 @@ static int runPages(const char *page_name, const int stop_on_page_done)
if (ors_read_fd > 0)
close(ors_read_fd);
ors_read_fd = -1;
set_select_fd();
gGuiRunning = 0;
return 0;
}
......
......@@ -21,6 +21,8 @@
#include "twmsg.h"
void set_select_fd();
void gui_msg(const char* text);
void gui_warn(const char* text);
void gui_err(const char* text);
......
......@@ -34,6 +34,7 @@ extern "C" {
#include "../twcommon.h"
}
#include "../minuitwrp/minui.h"
#include "gui.hpp"
#include "rapidxml.hpp"
#include "objects.hpp"
......@@ -83,6 +84,7 @@ public:
// and write it to the terminal
// this currently works through gui.cpp calling terminal_pty_read below
g_pty_fd = fdMaster;
set_select_fd();
return true;
}
else {
......@@ -174,6 +176,7 @@ public:
}
close(fdMaster);
g_pty_fd = fdMaster = -1;
set_select_fd();
int status;
waitpid(pid, &status, WNOHANG); // avoid zombies but don't hang if the child is still alive and we got here due to some error
pid = 0;
......
......@@ -30,6 +30,7 @@
<string name="sdext">SD-EXT</string>
<string name="adopted_data">Adopted Data</string>
<string name="adopted_storage">Adopted Storage</string>
<string name="autostorage">Storage</string>
<!-- GUI XML strings -->
<string name="twrp_header">Team Win Recovery Project</string>
......
......@@ -25,8 +25,8 @@
struct mtpmsg {
int message_type; // 1 is add, 2 is remove, see above
unsigned int storage_id;
const char* display;
const char* path;
char display[1024];
char path[1024];
uint64_t maxFileSize;
};
......
......@@ -170,7 +170,7 @@ int twmtp_MtpServer::mtppipe_thread(void)
if (mtp_message.storage_id) {
long reserveSpace = 1;
bool removable = false;
MtpStorage* storage = new MtpStorage(mtp_message.storage_id, mtp_message.path, mtp_message.display, reserveSpace, removable, mtp_message.maxFileSize, refserver);
MtpStorage* storage = new MtpStorage(mtp_message.storage_id, &mtp_message.path[0], &mtp_message.display[0], reserveSpace, removable, mtp_message.maxFileSize, refserver);
server->addStorage(storage);
MTPD("mtppipe done adding storage\n");
} else {
......
......@@ -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) {