vold2: Get mounting/unmounting/formatting/sharing working Signed-off-by: San Mehat <[email protected]>
diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 024645d..4a24ff7 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp
@@ -18,6 +18,8 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <fcntl.h> +#include <linux/kdev_t.h> #define LOG_TAG "Vold" @@ -27,7 +29,7 @@ #include "VolumeManager.h" #include "DirectVolume.h" -#include "ErrorCode.h" +#include "ResponseCode.h" VolumeManager *VolumeManager::sInstance = NULL; @@ -41,6 +43,7 @@ mBlockDevices = new BlockDeviceCollection(); mVolumes = new VolumeCollection(); mBroadcaster = NULL; + mUsbMassStorageConnected = false; } VolumeManager::~VolumeManager() { @@ -60,6 +63,37 @@ return 0; } +void VolumeManager::notifyUmsConnected(bool connected) { + char msg[255]; + + if (connected) { + mUsbMassStorageConnected = true; + } else { + mUsbMassStorageConnected = false; + } + snprintf(msg, sizeof(msg), "Share method ums now %s", + (connected ? "available" : "unavailable")); + + getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange, + msg, false); +} + +void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) { + const char *name = evt->findParam("SWITCH_NAME"); + const char *state = evt->findParam("SWITCH_STATE"); + + if (!strcmp(name, "usb_mass_storage")) { + + if (!strcmp(state, "online")) { + notifyUmsConnected(true); + } else { + notifyUmsConnected(false); + } + } else { + LOGW("Ignoring unknown switch '%s'", name); + } +} + void VolumeManager::handleBlockEvent(NetlinkEvent *evt) { const char *devpath = evt->findParam("DEVPATH"); @@ -68,13 +102,18 @@ bool hit = false; for (it = mVolumes->begin(); it != mVolumes->end(); ++it) { if (!(*it)->handleBlockEvent(evt)) { +#ifdef NETLINK_DEBUG + LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel()); +#endif hit = true; break; } } if (!hit) { +#ifdef NETLINK_DEBUG LOGW("No volumes handled block event for '%s'", devpath); +#endif } } @@ -86,13 +125,24 @@ asprintf(&buffer, "%s %s %d", (*i)->getLabel(), (*i)->getMountpoint(), (*i)->getState()); - cli->sendMsg(ErrorCode::VolumeListResult, buffer, false); + cli->sendMsg(ResponseCode::VolumeListResult, buffer, false); free(buffer); } - cli->sendMsg(ErrorCode::CommandOkay, "Volumes listed.", false); + cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false); return 0; } +int VolumeManager::formatVolume(const char *label) { + Volume *v = lookupVolume(label); + + if (!v) { + errno = ENOENT; + return -1; + } + + return v->formatVol(); +} + int VolumeManager::mountVolume(const char *label) { Volume *v = lookupVolume(label); @@ -101,12 +151,140 @@ return -1; } + return v->mountVol(); +} + +int VolumeManager::shareAvailable(const char *method, bool *avail) { + + if (strcmp(method, "ums")) { + errno = ENOSYS; + return -1; + } + + if (mUsbMassStorageConnected) + *avail = true; + else + *avail = false; + return 0; +} + +int VolumeManager::simulate(const char *cmd, const char *arg) { + + if (!strcmp(cmd, "ums")) { + if (!strcmp(arg, "connect")) { + notifyUmsConnected(true); + } else if (!strcmp(arg, "disconnect")) { + notifyUmsConnected(false); + } else { + errno = EINVAL; + return -1; + } + } else { + errno = EINVAL; + return -1; + } + return 0; +} + +int VolumeManager::shareVolume(const char *label, const char *method) { + Volume *v = lookupVolume(label); + + if (!v) { + errno = ENOENT; + return -1; + } + + /* + * Eventually, we'll want to support additional share back-ends, + * some of which may work while the media is mounted. For now, + * we just support UMS + */ + if (strcmp(method, "ums")) { + errno = ENOSYS; + return -1; + } + + if (v->getState() == Volume::State_NoMedia) { + errno = ENODEV; + return -1; + } + if (v->getState() != Volume::State_Idle) { + // You need to unmount manually befoe sharing errno = EBUSY; return -1; } - return v->mount(); + dev_t d = v->getDiskDevice(); + if ((MAJOR(d) == 0) && (MINOR(d) == 0)) { + // This volume does not support raw disk access + errno = EINVAL; + return -1; + } + + int fd; + char nodepath[255]; + snprintf(nodepath, + sizeof(nodepath), "/dev/block/vold/%d:%d", + MAJOR(d), MINOR(d)); + + if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0", O_WRONLY)) < 0) { + LOGE("Unable to open ums lunfile (%s)", strerror(errno)); + return -1; + } + + if (write(fd, nodepath, strlen(nodepath)) < 0) { + LOGE("Unable to write to ums lunfile (%s)", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + v->handleVolumeShared(); + return 0; +} + +int VolumeManager::unshareVolume(const char *label, const char *method) { + Volume *v = lookupVolume(label); + + if (!v) { + errno = ENOENT; + return -1; + } + + if (strcmp(method, "ums")) { + errno = ENOSYS; + return -1; + } + + if (v->getState() != Volume::State_Shared) { + errno = EINVAL; + return -1; + } + + dev_t d = v->getDiskDevice(); + + int fd; + char nodepath[255]; + snprintf(nodepath, + sizeof(nodepath), "/dev/block/vold/%d:%d", + MAJOR(d), MINOR(d)); + + if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0", O_WRONLY)) < 0) { + LOGE("Unable to open ums lunfile (%s)", strerror(errno)); + return -1; + } + + char ch = 0; + if (write(fd, &ch, 1) < 0) { + LOGE("Unable to write to ums lunfile (%s)", strerror(errno)); + close(fd); + return -1; + } + + close(fd); + v->handleVolumeUnshared(); + return 0; } int VolumeManager::unmountVolume(const char *label) { @@ -117,20 +295,35 @@ return -1; } + if (v->getState() == Volume::State_NoMedia) { + errno = ENODEV; + return -1; + } + if (v->getState() != Volume::State_Mounted) { + LOGW("Attempt to unmount volume which isn't mounted (%d)\n", + v->getState()); errno = EBUSY; return -1; } - return v->unmount(); + return v->unmountVol(); } +/* + * Looks up a volume by it's label or mount-point + */ Volume *VolumeManager::lookupVolume(const char *label) { VolumeCollection::iterator i; for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { - if (!strcmp(label, (*i)->getLabel())) - return (*i); + if (label[0] == '/') { + if (!strcmp(label, (*i)->getMountpoint())) + return (*i); + } else { + if (!strcmp(label, (*i)->getLabel())) + return (*i); + } } return NULL; }