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;
 }