vold2: Get mounting/unmounting/formatting/sharing working
Signed-off-by: San Mehat <san@google.com>
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;
}