diff options
author | codeworkx <codeworkx@cyanogenmod.org> | 2013-01-31 17:49:46 +0000 |
---|---|---|
committer | codeworkx <codeworkx@cyanogenmod.org> | 2013-03-04 16:54:41 +0000 |
commit | e336c0ca31f2768661063220e2a1cb83fd55b92d (patch) | |
tree | f54a7f23cc0b974a6aec41ae271d13e86dff38f4 | |
parent | fc1dcc1c50d2c6745d57dd7905c4e889a51e6af1 (diff) | |
download | system_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.mk | 16 | ||||
-rw-r--r-- | Ext4.cpp | 48 | ||||
-rw-r--r-- | Ext4.h | 1 | ||||
-rw-r--r-- | Volume.cpp | 148 | ||||
-rw-r--r-- | Volume.h | 2 |
5 files changed, 209 insertions, 6 deletions
@@ -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 := \ @@ -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]; @@ -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); }; @@ -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) { @@ -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(); }; |