summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcodeworkx <codeworkx@cyanogenmod.org>2013-01-31 17:49:46 +0000
committercodeworkx <codeworkx@cyanogenmod.org>2013-03-04 16:54:41 +0000
commite336c0ca31f2768661063220e2a1cb83fd55b92d (patch)
treef54a7f23cc0b974a6aec41ae271d13e86dff38f4
parentfc1dcc1c50d2c6745d57dd7905c4e889a51e6af1 (diff)
downloadsystem_vold-e336c0ca31f2768661063220e2a1cb83fd55b92d.zip
system_vold-e336c0ca31f2768661063220e2a1cb83fd55b92d.tar.gz
system_vold-e336c0ca31f2768661063220e2a1cb83fd55b92d.tar.bz2
vold: add support for ext4 media
Depends on: http://review.cyanogenmod.org/31202 http://review.cyanogenmod.org/31211 Result: http://pastebin.com/nzUbvW7K Change-Id: I5bd227e637f2a1ed4d13a2eb81390c56c953f482
-rw-r--r--Android.mk16
-rw-r--r--Ext4.cpp48
-rw-r--r--Ext4.h1
-rw-r--r--Volume.cpp148
-rw-r--r--Volume.h2
5 files changed, 209 insertions, 6 deletions
diff --git a/Android.mk b/Android.mk
index 79ea6a7..b53c8e7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -48,6 +48,14 @@ ifeq ($(BOARD_VOLD_DISC_HAS_MULTIPLE_MAJORS), true)
LOCAL_CFLAGS += -DVOLD_DISC_HAS_MULTIPLE_MAJORS
endif
+ifneq ($(TARGET_FUSE_SDCARD_UID),)
+LOCAL_CFLAGS += -DFUSE_SDCARD_UID=$(TARGET_FUSE_SDCARD_UID)
+endif
+
+ifneq ($(TARGET_FUSE_SDCARD_GID),)
+LOCAL_CFLAGS += -DFUSE_SDCARD_GID=$(TARGET_FUSE_SDCARD_GID)
+endif
+
LOCAL_MODULE := libvold
LOCAL_SRC_FILES := $(common_src_files)
@@ -95,6 +103,14 @@ ifneq ($(TARGET_USE_CUSTOM_SECOND_LUN_NUM),)
LOCAL_CFLAGS += -DCUSTOM_SECOND_LUN_NUM=$(TARGET_USE_CUSTOM_SECOND_LUN_NUM)
endif
+ifneq ($(TARGET_FUSE_SDCARD_UID),)
+LOCAL_CFLAGS += -DFUSE_SDCARD_UID=$(TARGET_FUSE_SDCARD_UID)
+endif
+
+ifneq ($(TARGET_FUSE_SDCARD_GID),)
+LOCAL_CFLAGS += -DFUSE_SDCARD_GID=$(TARGET_FUSE_SDCARD_GID)
+endif
+
LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
LOCAL_STATIC_LIBRARIES := \
diff --git a/Ext4.cpp b/Ext4.cpp
index 290489e..6bc06e4 100644
--- a/Ext4.cpp
+++ b/Ext4.cpp
@@ -40,7 +40,8 @@
#include "Ext4.h"
-#define MKEXT4FS_PATH "/system/bin/make_ext4fs";
+static char E2FSCK_PATH[] = "/system/bin/e2fsck";
+static char MKEXT4FS_PATH[] = "/system/bin/make_ext4fs";
extern "C" int logwrap(int argc, const char **argv, int background);
@@ -67,6 +68,51 @@ int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remo
return rc;
}
+int Ext4::check(const char *fsPath) {
+ bool rw = true;
+ if (access(E2FSCK_PATH, X_OK)) {
+ SLOGW("Skipping fs checks.\n");
+ return 0;
+ }
+
+ int rc = -1;
+ do {
+ const char *args[5];
+ args[0] = E2FSCK_PATH;
+ args[1] = "-p";
+ args[2] = "-f";
+ args[3] = fsPath;
+ args[4] = NULL;
+
+ rc = logwrap(4, args, 1);
+
+ switch(rc) {
+ case 0:
+ SLOGI("EXT4 Filesystem check completed OK.\n");
+ return 0;
+ case 1:
+ SLOGI("EXT4 Filesystem check completed, errors corrected OK.\n");
+ return 0;
+ case 2:
+ SLOGE("EXT4 Filesystem check completed, errors corrected, need reboot.\n");
+ return 0;
+ case 4:
+ SLOGE("EXT4 Filesystem errors left uncorrected.\n");
+ return 0;
+ case 8:
+ SLOGE("E2FSCK Operational error.\n");
+ errno = EIO;
+ return -1;
+ default:
+ SLOGE("EXT4 Filesystem check failed (unknown exit code %d).\n", rc);
+ errno = EIO;
+ return -1;
+ }
+ } while (0);
+
+ return 0;
+}
+
int Ext4::format(const char *fsPath) {
int fd;
const char *args[4];
diff --git a/Ext4.h b/Ext4.h
index a09b576..5a468b2 100644
--- a/Ext4.h
+++ b/Ext4.h
@@ -23,6 +23,7 @@ class Ext4 {
public:
static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
bool executable);
+ static int check(const char *fsPath);
static int format(const char *fsPath);
};
diff --git a/Volume.cpp b/Volume.cpp
index 422b566..f651277 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -45,11 +45,25 @@
#include "Volume.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
+#include "Ext4.h"
#include "Fat.h"
#include "Ntfs.h"
#include "Process.h"
#include "cryptfs.h"
+#ifndef FUSE_SDCARD_UID
+#define FUSE_SDCARD_UID 1023
+#endif
+#ifndef FUSE_SDCARD_GID
+#define FUSE_SDCARD_GID 1023
+#endif
+
+// Stringify defined values
+#define DO_STRINGIFY(str) #str
+#define STRINGIFY(str) DO_STRINGIFY(str)
+
+static char SDCARD_DAEMON_PATH[] = "/system/bin/sdcard";
+
extern "C" void dos_partition_dec(void const *pp, struct dos_partition *d);
extern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
@@ -89,6 +103,12 @@ const char *Volume::ASECDIR = "/mnt/asec";
*/
const char *Volume::LOOPDIR = "/mnt/obb";
+/*
+ * Path for fuse
+ */
+const char *Volume::FUSEDIR = "/mnt/fuse";
+
+
static const char *stateToStr(int state) {
if (state == Volume::State_Init)
return "Initializing";
@@ -450,6 +470,7 @@ int Volume::mountVol() {
for (i = 0; i < n; i++) {
char devicePath[255];
char *fstype = NULL;
+ bool isUnixFs = false;
sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),
MINOR(deviceNodes[i]));
@@ -490,6 +511,24 @@ int Volume::mountVol() {
continue;
}
+ } else if (strcmp(fstype, "ext4") == 0) {
+
+ isUnixFs = true;
+ if (Ext4::check(devicePath)) {
+ errno = EIO;
+ isUnixFs = false;
+ /* Badness - abort the mount */
+ SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno));
+ setState(Volume::State_Idle);
+ free(fstype);
+ return -1;
+ }
+
+ if (Ext4::doMount(devicePath, "/mnt/secure/staging", false, false, false)) {
+ SLOGE("%s failed to mount via EXT4 (%s)\n", devicePath, strerror(errno));
+ continue;
+ }
+
} else if (strcmp(fstype, "ntfs") == 0) {
if (Ntfs::doMount(devicePath, "/mnt/secure/staging", false, false, false,
@@ -507,7 +546,15 @@ int Volume::mountVol() {
}
free(fstype);
+
+ } else {
+ // Unsupported filesystem
+ errno = ENODATA;
+ setState(Volume::State_Idle);
+ free(fstype);
+ return -1;
}
+
SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());
protectFromAutorunStupidity();
@@ -524,11 +571,66 @@ int Volume::mountVol() {
* Now that the bindmount trickery is done, atomically move the
* whole subtree to expose it to non priviledged users.
*/
- if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) {
- SLOGE("Failed to move mount (%s)", strerror(errno));
- umount("/mnt/secure/staging");
- setState(Volume::State_Idle);
- return -1;
+ if (isUnixFs) {
+ /*
+ * In case of a unix filesystem we're using the sdcard daemon
+ * to expose the subtree to non privileged users to avoid
+ * permission issues for data created by apps.
+ */
+ const char* label = getLabel();
+ char* fuseSrc = (char*) malloc(strlen(FUSEDIR) + strlen("/") + strlen(label) + 1);
+ sprintf(fuseSrc, "%s/%s", FUSEDIR, label);
+ bool failed = false;
+
+ // Create fuse dir if not exists
+ if (access(fuseSrc, R_OK | W_OK)) {
+ if (mkdir(fuseSrc, 0775)) {
+ SLOGE("Failed to create %s (%s)", fuseSrc, strerror(errno));
+ failed = true;
+ }
+ }
+
+ // Move subtree to fuse dir
+ if (!failed && doMoveMount("/mnt/secure/staging", fuseSrc, false)) {
+ SLOGE("Failed to move mount (%s)", strerror(errno));
+ umount("/mnt/secure/staging");
+ failed = true;
+ }
+
+ // Set owner and group on fuse dir
+ if (!failed && chown(fuseSrc, FUSE_SDCARD_UID, FUSE_SDCARD_GID)) {
+ SLOGE("Failed to set owner/group on %s (%s)", fuseSrc, strerror(errno));
+ failed = true;
+ }
+
+ // Set permissions (775) on fuse dir
+ if (!failed && chmod(fuseSrc, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH)) {
+ SLOGE("Failed to set permissions on %s (%s)", fuseSrc, strerror(errno));
+ failed = true;
+ }
+
+ // Invoke the sdcard daemon to expose it
+ if(!failed && doFuseMount(fuseSrc, getMountpoint())) {
+ SLOGE("Failed to fuse mount (%s) -> (%s)", fuseSrc, getMountpoint());
+ failed = true;
+ }
+
+ free(fuseSrc);
+
+ if (failed) {
+ setState(Volume::State_Idle);
+ return -1;
+ }
+
+ } else {
+
+ if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) {
+ SLOGE("Failed to move mount (%s)", strerror(errno));
+ umount("/mnt/secure/staging");
+ setState(Volume::State_Idle);
+ return -1;
+ }
+
}
setState(Volume::State_Mounted);
mCurrentlyMountedKdev = deviceNodes[i];
@@ -638,6 +740,27 @@ int Volume::doMoveMount(const char *src, const char *dst, bool force) {
return -1;
}
+int Volume::doFuseMount(const char *src, const char *dst) {
+ if (access(SDCARD_DAEMON_PATH, X_OK)) {
+ SLOGE("Can't invoke sdcard daemon.\n");
+ return -1;
+ }
+ const char* const args[] = { "sdcard", src, dst, STRINGIFY(FUSE_SDCARD_UID), STRINGIFY(FUSE_SDCARD_GID), NULL };
+ pid_t fusePid;
+
+ fusePid=fork();
+
+ if (fusePid == 0) {
+ SLOGW("Invoking sdcard daemon (%s) -> (%s)", src, dst);
+ if (execv(SDCARD_DAEMON_PATH, (char* const*)args) == -1) {
+ SLOGE("Failed to invoke the sdcard daemon!");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
int Volume::doUnmount(const char *path, bool force) {
int retries = 10;
@@ -675,6 +798,9 @@ int Volume::doUnmount(const char *path, bool force) {
int Volume::unmountVol(bool force, bool revert) {
int i, rc;
const char* externalStorage = getenv("EXTERNAL_STORAGE");
+ const char* label = getLabel();
+ char* fuseDir = (char*) malloc(strlen(FUSEDIR) + strlen("/") + strlen(label) + 1);
+ sprintf(fuseDir, "%s/%s", FUSEDIR, label);
if (getState() != Volume::State_Mounted) {
SLOGE("Volume %s unmount request when not mounted", getLabel());
@@ -709,6 +835,16 @@ int Volume::unmountVol(bool force, bool revert) {
}
/*
+ * Unmount the actual block device from fuse dir if exists
+ */
+ if (!access(fuseDir, R_OK | W_OK)) {
+ if (doUnmount(fuseDir, force)) {
+ SLOGE("Failed to unmount %s (%s)", fuseDir, strerror(errno));
+ goto out_nomedia;
+ }
+ }
+
+ /*
* Finally, unmount the actual block device from the staging dir
*/
if (doUnmount(getMountpoint(), force)) {
@@ -730,6 +866,7 @@ int Volume::unmountVol(bool force, bool revert) {
setState(Volume::State_Idle);
mCurrentlyMountedKdev = -1;
+ free(fuseDir);
return 0;
/*
@@ -756,6 +893,7 @@ fail_republish:
out_nomedia:
setState(Volume::State_NoMedia);
+ free(fuseDir);
return -1;
}
int Volume::initializeMbr(const char *deviceNode) {
diff --git a/Volume.h b/Volume.h
index 9dd263e..5e90740 100644
--- a/Volume.h
+++ b/Volume.h
@@ -46,6 +46,7 @@ public:
static const char *ASECDIR;
static const char *LOOPDIR;
+ static const char *FUSEDIR;
protected:
char *mLabel;
@@ -105,6 +106,7 @@ private:
int createBindMounts();
int doUnmount(const char *path, bool force);
int doMoveMount(const char *src, const char *dst, bool force);
+ int doFuseMount(const char *src, const char *dst);
void protectFromAutorunStupidity();
};